Séance 4 : Router et navigation
🎯 Objectifs
Maîtriser navigation avancée avec Vue Router.
Gérer routes dynamiques et sécurisées.
📖 Partie théorique
Routes dynamiques et imbriquées
Paramètres de route
Les routes dynamiques capturent des valeurs variables dans l'URL (:id
, :slug
).
// Configuration des routes
const routes = [
{ path: '/task/:id', component: TaskDetail, props: true },
{ path: '/user/:userId/task/:taskId', component: TaskDetail },
{ path: '/profile/:userId?', component: UserProfile }, // Optionnel
]
Accès aux paramètres :
// Dans le composant
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
const taskId = route.params.id
</script>
Routes imbriquées
Organisation hiérarchique avec composants parent/enfant.
// Structure imbriquée
const routes = [
{
path: '/dashboard',
component: DashboardLayout,
children: [
{ path: '', component: DashboardHome }, // /dashboard
{ path: 'tasks', component: TaskList }, // /dashboard/tasks
{ path: 'tasks/:id', component: TaskDetail }, // /dashboard/tasks/123
]
}
]
<!-- DashboardLayout.vue -->
<template>
<div class="dashboard">
<nav>
<router-link to="/dashboard/tasks">Tâches</router-link>
</nav>
<main>
<router-view></router-view> <!-- Contenu des routes enfants -->
</main>
</div>
</template>
Navigation programmatique :
const router = useRouter()
// Différentes façons de naviguer
router.push('/tasks/123')
router.push({ name: 'TaskDetail', params: { id: 123 } })
router.push({ path: '/tasks', query: { status: 'pending' } })
Gestion des erreurs
Pages d'erreur et redirections pour une meilleure expérience utilisateur.
Page 404 personnalisée
<!-- NotFound.vue -->
<template>
<div class="error-page">
<h1>404 - Page non trouvée</h1>
<p>La page demandée n'existe pas.</p>
<router-link to="/">Retour à l'accueil</router-link>
</div>
</template>
Configuration des routes d'erreur
const routes = [
// Autres routes...
// Redirections
{ path: '/old-url', redirect: '/new-url' },
// Redirection conditionnelle
{
path: '/user/:id',
redirect: to => `/profile/${to.params.id}`
},
// Page 404 (toujours en dernier)
{
path: '/:pathMatch(.*)*',
component: NotFound
}
]
Gestion des erreurs de navigation
// Intercepter les erreurs de chargement
router.onError((error) => {
if (error.message.includes('Loading chunk')) {
// Erreur de réseau, recharger la page
window.location.reload()
}
})
Routes et meta
Il est possible d'ajouter des métadonnées aux routes pour diverses utilisations (authentification, titres, etc.).
const routes = [
{
path: '/dashboard',
component: DashboardLayout,
meta: { requiresAuth: true, title: 'Tableau de bord' },
children: [
{ path: 'analytics', component: AnalyticsPage, meta: { title: 'Analyse' } },
{ path: 'settings', component: SettingsPage, meta: { title: 'Paramètres' } }
]
}
]
Usage dans les composants :
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route.meta.title) // Titre de la page
</script>
Le meta peut aussi être utilisé pour des guards ou pour changer le titre de la page dynamiquement.
Guards
Fonctions de contrôle d’accès (
beforeEach
, meta).Protection des routes sensibles (authentification).
Concepts clés :
Global Guards : s’appliquent à toutes les navigations.
Per-Route Guards : spécifiques à certaines routes.
In-Component Guards : définis dans les composants.
Guard global :
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && !isAuthenticated()) {
next('/login')
} else {
next()
}
})
Guard par route :
const routes = [
{
path: '/admin',
component: AdminPanel,
meta: { requiresAuth: true, role: 'admin' },
beforeEnter: (to, from, next) => {
// Vérification spécifique à cette route
if (!user.isAdmin) {
next('/forbidden')
} else {
next()
}
}
}
]
Guard dans composant :
<script setup>
import { onBeforeRouteLeave } from 'vue-router'
const hasUnsavedChanges = ref(false)
// Confirmation avant de quitter
onBeforeRouteLeave((to, from, next) => {
if (hasUnsavedChanges.value) {
const leave = confirm('Modifications non sauvées, continuer ?')
next(leave)
} else {
next()
}
})
</script>
Mise à jour du title de la page
router.afterEach((to) => {
if (to.meta.title) {
document.title = to.meta.title
}
})
Lazy loading (Chargement différé)
Chargement des composants uniquement quand nécessaire pour optimiser les performances.
Import dynamique
// ❌ Import classique - chargé immédiatement
import Home from '@/views/Home.vue'
// ✅ Import dynamique - chargé à la demande
const routes = [
{
path: '/home',
component: () => import('@/views/Home.vue')
}
]
Composant de chargement
<!-- App.vue -->
<template>
<Suspense>
<router-view></router-view>
<template #fallback>
<div class="loading">Chargement...</div>
</template>
</Suspense>
</template>
📝 Travaux pratiques
Ajouter route
/task/:id
.Mettre en place un guard d’accès (auth simulée).
Créer une page 404 personnalisée.
Last updated