# La Gestion du Routage avec Vue Router
## Introduction : Naviguer dans les Applications Vue.js
Dans le monde moderne du développement web, les *Single-Page Applications* (SPA) ont révolutionné la manière dont les utilisateurs interagissent avec les interfaces. Contrairement aux applications traditionnelles qui nécessitent un rechargement complet de la page pour chaque nouvelle vue, une SPA charge le contenu de manière dynamique, offrant une expérience utilisateur fluide et réactive.
Cependant, cette fluidité apporte son propre défi : comment gérer les différentes "pages" ou "vues" de notre application sans recharger la page ? Comment s'assurer que l'URL du navigateur reflète l'état actuel de l'application, permettant aux utilisateurs de mettre en signet des vues spécifiques ou d'utiliser les boutons "précédent" et "suivant" du navigateur ?
C'est là qu'intervient le **routage côté client**. Pour les applications Vue.js, la solution officielle et la plus populaire est **Vue Router**. Cet outil puissant nous permet de mapper les chemins d'URL aux composants Vue, de gérer la navigation, de passer des données entre les vues et de protéger l'accès à certaines parties de l'application.
Dans cette leçon, nous allons explorer Vue Router en profondeur, de son installation à ses fonctionnalités avancées, pour que vous puissiez maîtriser la gestion du routage dans vos applications Vue.js.
## Qu'est-ce que le Routage et Pourquoi Vue Router ?
### Le Problème du Routage Côté Client
Imaginez une application web où vous avez une page d'accueil, une page "À Propos" et une page de profil utilisateur. Dans une application multipage classique, cliquer sur un lien vers la page "À Propos" provoquerait un nouveau chargement de page et le serveur enverrait le fichier HTML correspondant.
Dans une SPA, ce n'est pas le cas. Une fois l'application chargée, elle reste sur la même page HTML (généralement `index.html`). Lorsque l'utilisateur clique sur un lien, nous voulons :
1. **Mettre à jour l'URL** dans la barre d'adresse du navigateur.
2. **Afficher le composant Vue** approprié à cette URL.
3. **Permettre la navigation** avant/arrière avec l'historique du navigateur.
4. **Récupérer des informations** de l'URL (par exemple, un ID d'utilisateur).
Sans un système de routage, gérer tout cela manuellement deviendrait rapidement un cauchemar de logique conditionnelle complexe.
### La Solution Vue Router
**Vue Router** est la bibliothèque de routage officielle pour Vue.js. Elle s'intègre parfaitement avec le framework et fournit une API intuitive pour gérer tous les aspects du routage côté client.
Voici ses avantages clés :
* **Déclaration de routes simple** : Définissez vos routes comme un tableau d'objets JavaScript.
* **Routage dynamique** : Capturez des segments d'URL comme des paramètres pour afficher des données spécifiques (ex: `/users/123`).
* **Navigation programmatique** : Naviguez par code, pas seulement par des liens.
* **Gardes de navigation (Navigation Guards)** : Interceptez la navigation pour implémenter des logiques d'authentification, d'autorisation ou de confirmation.
* **Gestion de l'historique** : Supporte les modes "hash" et "history" pour des URLs propres.
* **Liens actifs** : Stylisez automatiquement les liens correspondant à la route actuelle.
En bref, Vue Router nous abstrait la complexité de la manipulation de l'historique du navigateur et de la logique de rendu conditionnel, nous permettant de nous concentrer sur la construction de nos composants.
## Installation et Premiers Pas
Pour cette leçon, nous utiliserons **Vue Router 4**, la version compatible avec Vue 3.
### Installation
Si vous utilisez Vue CLI ou Vite pour créer votre projet, Vue Router peut souvent être ajouté pendant le processus de création. Sinon, vous pouvez l'installer manuellement via npm ou yarn :
```bash
npm install vue-router@4
# ou
yarn add vue-router@4
Configuration Basique
Une fois installé, la première étape consiste à configurer Vue Router dans votre application. Nous créons généralement un dossier router à la racine de votre dossier src, avec un fichier index.js à l'intérieur.
Voici un exemple de configuration de base :
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import HomeView from '../views/HomeView.vue'; // Assurez-vous que le chemin est correct
import AboutView from '../views/AboutView.vue';
// 1. Définir vos routes
// Chaque objet de route mappe un chemin (path) à un composant.
const routes = [
{
path: '/', // Le chemin de l'URL pour cette route
name: 'Home', // Un nom unique pour la route (utile pour la navigation programmatique)
component: HomeView // Le composant Vue à rendre lorsque cette route est active
},
{
path: '/about',
name: 'About',
component: AboutView
// Vous pouvez également utiliser un import dynamique pour des chargements paresseux (lazy loading) :
// component: () => import('../views/AboutView.vue')
}
];
// 2. Créer l'instance du routeur
const router = createRouter({
history: createWebHistory(), // Utilise l'API History du navigateur pour des URLs propres
routes // Vos routes définies
});
// 3. Exporter l'instance du routeur
export default router;
Ensuite, vous devez "dire" à votre application Vue d'utiliser ce routeur. Cela se fait généralement dans votre fichier main.js (ou main.ts si vous utilisez TypeScript) :
// src/main.js
import { createApp } from 'vue';
import App from './App.vue';
import router from './router'; // Importe l'instance de votre routeur
createApp(App)
.use(router) // Indique à l'application Vue d'utiliser Vue Router
.mount('#app');
Maintenant, votre application Vue est équipée d'un routeur !
Composants de Base de Vue Router : <router-view> et <router-link>
Avec le routeur configuré, nous avons besoin de deux composants fournis par Vue Router pour interagir avec le système de routage dans nos templates :
-
<router-view />C'est un composant "placeholder" où le composant de la route actuelle sera rendu. Il est généralement placé dans votre composant racine (App.vue) ou dans un composant de layout principal.- Rôle : Il agit comme une "prise" où Vue Router branche le composant associé à l'URL actuelle.
-
<router-link to="...">C'est le composant privilégié pour créer des liens de navigation. Il est rendu comme une balise<a>par défaut, mais il intercepte le clic pour empêcher un rechargement complet de la page, permettant au routeur de gérer la transition.- Propriété
to: Elle spécifie la destination. Elle peut être une simple chaîne de caractères (chemin) ou un objet pour une navigation plus complexe (avec des noms de routes, des paramètres, etc.). - Classes actives : Ajoute automatiquement des classes CSS (
router-link-activeetrouter-link-exact-active) aux liens dont la destination correspond à la route actuelle, ce qui est idéal pour le stylisation des menus.
- Propriété
Voici comment vous utiliseriez ces composants dans votre App.vue :
<!-- src/App.vue -->
<template>
<div id="app">
<nav>
<!-- Utilisation de <router-link> pour la navigation déclarative -->
<router-link to="/">Accueil</router-link> |
<router-link to="/about">À Propos</router-link>
<!-- Des liens avec des classes de style automatiques -->
</nav>
<!-- Le composant de la route active sera rendu ici -->
<router-view />
</div>
</template>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
nav {
padding: 30px;
}
nav a {
font-weight: bold;
color: #2c3e50;
text-decoration: none; /* Enlève le soulignement par défaut */
}
/* Style pour le lien actif (quand la route du lien est la route actuelle) */
nav a.router-link-exact-active {
color: #42b983; /* Une couleur verte distinctive */
}
</style>
Avec cette configuration, si vous démarrez votre application, vous devriez voir les liens "Accueil" et "À Propos". Cliquer dessus changera l'URL et affichera le composant correspondant dans la <router-view>, sans recharger la page.
Définition des Routes
La puissance de Vue Router réside dans la flexibilité avec laquelle vous pouvez définir vos routes.
Objets Route
Chaque objet dans le tableau routes de votre configuration est un objet de route. Il peut avoir plusieurs propriétés clés :
path(chaîne) : Le chemin de l'URL. Peut inclure des paramètres dynamiques (voir ci-dessous).name(chaîne) : Un nom unique pour la route. Utile pour la navigation programmatique et pour des routes plus complexes.component(composant Vue) : Le composant à rendre lorsque cette route est active.components(objet) : Pour les routes avec des vues nommées (plusieurs<router-view>dans un même layout).redirect(chaîne ou objet) : Pour rediriger une route vers une autre.- Ex:
{ path: '/home', redirect: '/' }
- Ex:
alias(chaîne ou tableau de chaînes) : Fournit des chemins alternatifs à la même route.- Ex:
{ path: '/user/:id', component: User, alias: '/profile/:id' }
- Ex:
children(tableau) : Pour les routes imbriquées (nested routes). Permet de définir une hiérarchie d'URL et de composants.meta(objet) : Un objet arbitraire pour stocker des métadonnées, souvent utilisé avec les gardes de navigation (ex:{ meta: { requiresAuth: true } }).props(booléen, objet ou fonction) : Permet de passer les paramètres de la route ou des props statiques directement au composant (voir ci-dessous).
Routage Dynamique (Paramètres de Route)
Souvent, vous aurez besoin de passer des informations à votre composant via l'URL, par exemple l'ID d'un utilisateur ou d'un produit. Vue Router utilise un système de paramètres de route.
Pour définir un paramètre de route, utilisez le préfixe : dans le path :
// src/router/index.js (ajout d'une nouvelle route)
import UserDetailView from '../views/UserDetailView.vue';
const routes = [
// ... autres routes
{
path: '/users/:id', // ':id' est un paramètre dynamique
name: 'UserDetail',
component: UserDetailView
}
];
Dans votre composant UserDetailView, vous pouvez accéder à ce paramètre via l'objet $route (dans l'Options API) ou via la fonction useRoute() (dans la Composition API) :
<!-- src/views/UserDetailView.vue -->
<template>
<div>
<h2>Détail de l'utilisateur</h2>
<p>ID de l'utilisateur : {{ userId }}</p>
<p>Nom de l'utilisateur : {{ user?.name || 'Chargement...' }}</p>
</div>
</template>
<script>
import { useRoute } from 'vue-router';
import { ref, watchEffect } from 'vue';
export default {
// Option API
// data() {
// return {
// user: null
// };
// },
// created() {
// this.fetchUser(this.$route.params.id);
// },
// watch: {
// '$route.params.id'(newId) {
// this.fetchUser(newId);
// }
// },
// methods: {
// fetchUser(id) {
// // Simule une requête API
// this.user = { id: id, name: `Utilisateur ${id}` };
// }
// }
// Composition API
setup() {
const route = useRoute(); // Accède à l'objet de la route actuelle
const user = ref(null);
// Utilisez watchEffect pour réagir aux changements de route.params.id
watchEffect(() => {
const userId = route.params.id; // Accède au paramètre 'id'
if (userId) {
// Simule une requête API avec l'ID de l'utilisateur
// En production, vous feriez un appel réel à une API
user.value = { id: userId, name: `Utilisateur ${userId}` };
}
});
return {
userId: route.params.id, // Directement accessible pour le template
user
};
}
};
</script>
Pour naviguer vers cette route, vous pouvez utiliser <router-link> :
<!-- Dans App.vue ou un autre composant -->
<router-link to="/users/123">Voir l'utilisateur 123</router-link>
<router-link :to="{ name: 'UserDetail', params: { id: 456 }}">Voir l'utilisateur 456</router-link>
Propriétés props pour les Paramètres
Une meilleure pratique consiste à découpler vos composants de l'objet $route en passant les paramètres de route comme des props au composant. Cela rend le composant plus réutilisable et testable.
Pour ce faire, ajoutez props: true à la définition de votre route :
// src/router/index.js (mise à jour de la route UserDetail)
const routes = [
// ...
{
path: '/users/:id',
name: 'UserDetail',
component: UserDetailView,
props: true // Active le passage des paramètres de route comme des props
}
];
Ensuite, dans votre UserDetailView.vue, vous pouvez déclarer id comme une prop :
<!-- src/views/UserDetailView.vue (mise à jour) -->
<template>
<div>
<h2>Détail de l'utilisateur</h2>
<!-- Accédez à l'ID directement via la prop -->
<p>ID de l'utilisateur : {{ id }}</p>
<p>Nom de l'utilisateur : {{ user?.name || 'Chargement...' }}</p>
</div>
</template>
<script>
import { ref, watchEffect } from 'vue';
export default {
props: ['id'], // Déclare 'id' comme une prop
setup(props) { // Les props sont passées au setup dans la Composition API
const user = ref(null);
// watchEffect réagit aux changements de la prop 'id'
watchEffect(() => {
if (props.id) {
// Simule une requête API avec l'ID de l'utilisateur
user.value = { id: props.id, name: `Utilisateur ${props.id}` };
}
});
return {
user
};
}
};
</script>
Cette approche est fortement recommandée car elle rend vos composants plus agnostiques quant à la source de leurs données (qu'elles viennent de l'URL, d'un composant parent ou d'un store).
Navigation Programmatique
Bien que <router-link> soit excellent pour la navigation déclarative (dans les templates), il est parfois nécessaire de naviguer par programme, par exemple après la soumission d'un formulaire, une action utilisateur ou une redirection conditionnelle.
Vue Router fournit une API pour cela. Vous pouvez accéder à l'instance du routeur via this.$router dans l'Options API, ou via la fonction useRouter() dans la Composition API.
Méthodes Clés de Navigation
-
router.push(location):- La méthode la plus courante. Elle ajoute une nouvelle entrée à la pile d'historique du navigateur, de sorte que l'utilisateur peut utiliser le bouton "Retour".
locationpeut être une chaîne de chemin ou un objet de route.- Exemples :
// Naviguer vers un chemin router.push('/about'); // Naviguer vers une route nommée avec des paramètres router.push({ name: 'UserDetail', params: { id: 123 } }); // Naviguer avec une requête (query) router.push({ path: '/search', query: { q: 'vuejs' } });
-
router.replace(location):- Similaire à
push, mais elle remplace l'entrée actuelle dans la pile d'historique, au lieu d'en ajouter une nouvelle. Cela signifie que l'utilisateur ne pourra pas revenir à la route précédente en utilisant le bouton "Retour". - Utile pour les redirections (ex: après connexion/déconnexion).
- Exemple :
router.replace('/dashboard');
- Similaire à
-
router.go(n):- Permet de naviguer en avant ou en arrière dans l'historique de la pile.
nest un entier. router.go(-1): Revenir à la page précédente (équivalent à cliquer sur le bouton "Retour").router.go(1): Avancer à la page suivante.router.go(-2): Revenir de deux pages.
- Permet de naviguer en avant ou en arrière dans l'historique de la pile.
Voici un exemple d'utilisation dans un composant :
<!-- src/components/NavigationButtons.vue -->
<template>
<div>
<button @click="goToHomePage">Aller à l'Accueil</button>
<button @click="goToUserDetail(789)">Voir l'utilisateur 789</button>
<button @click="goBack">Retour</button>
</div>
</template>
<script>
import { useRouter } from 'vue-router'; // Importe useRouter
export default {
setup() {
const router = useRouter(); // Récupère l'instance du routeur
const goToHomePage = () => {
router.push('/'); // Navigue vers la route d'accueil
};
const goToUserDetail = (id) => {
router.push({ name: 'UserDetail', params: { id: id } }); // Navigue vers une route nommée avec un paramètre
};
const goBack = () => {
router.go(-1); // Revenir à la page précédente
};
return {
goToHomePage,
goToUserDetail,
goBack
};
}
};
</script>
Gardes de Navigation (Navigation Guards)
Les gardes de navigation (ou "navigation guards") sont des fonctions ou des crochets que Vue Router exécute avant ou après une navigation. Ils sont essentiels pour implémenter des logiques de sécurité (authentification, autorisation), des confirmations (quand un utilisateur quitte un formulaire non sauvegardé) ou des récupérations de données.
Les gardes de navigation peuvent être définies à différents niveaux :
- Globales : S'appliquent à toutes les routes.
- Par Route : Définies directement sur l'objet de la route.
- Dans les Composants : Définies à l'intérieur des composants de la vue.
Chaque garde de navigation reçoit jusqu'à trois arguments :
to: L'objet de la route vers laquelle on navigue.from: L'objet de la route d'où l'on vient.next: Une fonction à appeler pour résoudre la garde.next(): Continue la navigation versto.next(false): Annule la navigation.next('/path')ounext({ name: 'RouteName' }): Redirige vers un nouveau chemin/route.next(error): Abandonne la navigation et passe une erreur au gestionnaire d'erreurs du routeur.
Types de Gardes
Gardes Globales
router.beforeEach((to, from, next) => { ... }): Exécutée avant chaque navigation. C'est le lieu idéal pour les vérifications d'authentification ou d'autorisation.router.beforeResolve((to, from, next) => { ... }): Exécutée juste avant que la navigation ne soit confirmée, après tous les gardesbeforeEachet les gardesbeforeEnterde la route.router.afterEach((to, from) => { ... }): Exécutée après chaque navigation. N'accepte pasnext, utilisée pour des effets secondaires comme l'analyse (analytics) ou le défilement de la fenêtre.
Gardes par Route
-
beforeEnter(to, from, next): Définie directement dans la configuration d'un objet de route. S'exécute uniquement lorsque cette route est entrée.// src/router/index.js { path: '/admin', name: 'AdminPanel', component: AdminPanel, meta: { requiresAuth: true, requiresAdmin: true }, beforeEnter: (to, from, next) => { // Vérifier si l'utilisateur a les droits d'administrateur const isAdmin = /* votre logique */; if (isAdmin) { next(); } else { next('/'); // Rediriger vers l'accueil si non admin } } }
Gardes dans les Composants
Ces gardes sont définies directement à l'intérieur des composants de la vue.
beforeRouteEnter(to, from, next): S'exécute avant que le composant ne soit créé. N'a pas accès àthiscar le composant n'est pas encore instancié. Pour y accéder, utiliseznext(vm => { /* vm est l'instance du composant */ }).beforeRouteUpdate(to, from, next): S'exécute lorsque la même route est réutilisée (par exemple, si seul un paramètre de route change, comme/users/1vers/users/2). A accès àthis.beforeRouteLeave(to, from, next): S'exécute avant de quitter la route du composant. Utile pour les alertes "Voulez-vous vraiment quitter ? Vos changements ne seront pas sauvegardés". A accès àthis.
Exemple de Garde beforeEach (Authentification)
Un cas d'utilisation courant est la protection de routes nécessitant une authentification. Nous pouvons utiliser une méta-propriété meta.requiresAuth sur les routes et un garde global beforeEach.
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import HomeView from '../views/HomeView.vue';
import DashboardView from '../views/DashboardView.vue';
import LoginView from '../views/LoginView.vue';
const routes = [
{
path: '/',
name: 'Home',
component: HomeView
},
{
path: '/dashboard',
name: 'Dashboard',
component: DashboardView,
meta: { requiresAuth: true } // Cette route nécessite une authentification
},
{
path: '/login',
name: 'Login',
component: LoginView
}
];
const router = createRouter({
history: createWebHistory(),
routes
});
// Garde de navigation globale
router.beforeEach((to, from, next) => {
// Vérifie si la route vers laquelle on navigue nécessite une authentification
const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
// Simulez une vérification d'authentification (par exemple, un token dans localStorage)
const isAuthenticated = localStorage.getItem('userToken'); // Ou vérifiez un état dans Vuex/Pinia
if (requiresAuth && !isAuthenticated) {
// Si la route nécessite une authentification et l'utilisateur n'est pas authentifié,
// redirigez-le vers la page de connexion.
console.log('Navigation bloquée : nécessite une authentification.');
next({ name: 'Login', query: { redirect: to.fullPath } }); // Passe la route originale comme paramètre de query
} else {
// Sinon, continuez la navigation
console.log('Navigation autorisée.');
next();
}
});
export default router;
Dans cet exemple, si un utilisateur non authentifié tente d'accéder à /dashboard, il sera redirigé vers /login. Après une connexion réussie, vous pouvez utiliser router.push(this.$route.query.redirect || '/') pour le renvoyer à sa destination initiale.
Modes d'Historique
Vue Router offre deux modes principaux pour gérer l'historique du navigateur et les URLs :
Mode Hachage (Hash Mode)
- Fonctionnement : Utilise un caractère
hash(#) dans l'URL. Par exemple,http://localhost:8080/#/about. Le contenu après le#n'est pas envoyé au serveur. - Avantages :
- Aucune configuration serveur requise : Fonctionne "out of the box" sur n'importe quel serveur web, car tout le routage est géré côté client après le
#.
- Aucune configuration serveur requise : Fonctionne "out of the box" sur n'importe quel serveur web, car tout le routage est géré côté client après le
- Inconvénients :
- URLs moins esthétiques : Le
#peut sembler moins "propre". - SEO potentiellement réduit : Bien que Google et d'autres moteurs de recherche majeurs puissent indexer les URLs avec hachage, le mode histoire est généralement préféré pour le SEO.
- URLs moins esthétiques : Le
- Configuration :
C'était le mode par défaut dans Vue Router 3.import { createWebHashHistory } from 'vue-router'; const router = createRouter({ history: createWebHashHistory(), // Active le mode hachage routes });
Mode Histoire (History Mode)
- Fonctionnement : Utilise l'API History du navigateur (
pushState,replaceState) pour manipuler l'URL sans recharger la page. Les URLs sont "propres" (ex:http://localhost:8080/about). - Avantages :
- URLs propres et sémantiques : Meilleure expérience utilisateur et SEO.
- Inconvénients :
- Configuration serveur requise : Si un utilisateur accède directement à
http://localhost:8080/about(c'est-à-dire en tapant l'URL ou en rafraîchissant la page), le serveur recevra une requête pour/about. Si le serveur n'est pas configuré pour renvoyerindex.htmlpour toutes les routes inconnues, il répondra par une erreur 404. Vous devez configurer votre serveur pour qu'il redirige toutes les requêtes versindex.htmlpour les routes de votre application.- Exemple (Apache) :
.htaccess<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^index\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.html [L] </IfModule> - Exemple (Nginx) :
location / { try_files $uri $uri/ /index.html; }
- Exemple (Apache) :
- Configuration serveur requise : Si un utilisateur accède directement à
- Configuration :
C'est le mode par défaut et recommandé pour Vue Router 4.import { createWebHistory } from 'vue-router'; const router = createRouter({ history: createWebHistory(), // Active le mode histoire (recommandé pour Vue 3) routes });
Le choix entre les deux modes dépend de vos besoins spécifiques et de votre capacité à configurer le serveur. Pour la plupart des applications modernes, le mode histoire est préféré.
Conclusion
La gestion du routage est un pilier fondamental de toute Single-Page Application moderne, et Vue Router s'impose comme la solution incontournable pour les projets Vue.js.
Au cours de cette leçon, nous avons parcouru les concepts essentiels :
- Comprendre le problème du routage côté client et pourquoi une bibliothèque comme Vue Router est indispensable.
- Installer et configurer Vue Router de manière basique.
- Maîtriser les composants clés
<router-view>et<router-link>pour la navigation déclarative. - Apprendre à définir des routes avec des paramètres dynamiques et à les passer comme
propspour des composants plus modulaires. - Utiliser la navigation programmatique via
router.push(),router.replace()etrouter.go()pour des interactions utilisateur plus complexes. - Exploiter la puissance des gardes de navigation pour contrôler le flux de l'application, implémenter l'authentification et gérer les permissions.
- Distinguer les modes d'historique (hash vs. history) et leurs implications pour le déploiement.
Vue Router est un outil robuste qui vous permet de construire des applications réactives et navigables avec élégance. Sa flexibilité vous accompagnera dans la création d'applications allant des plus simples aux plus complexes.
La meilleure façon de maîtriser Vue Router est de pratiquer. N'hésitez pas à expérimenter avec les différents types de routes, les gardes, et les méthodes de navigation pour solidifier vos connaissances. Bonne route dans vos projets Vue.js !