Cours Vue.js · Module 10: Vue Router

Routes dynamiques

2 min de lecture
Dans cette leçon6

Chaque module de la base NOVA LAB possède son identifiant unique. De la même façon, on peut créer des chemins dynamiques dans l'application - des routes qui acceptent des paramètres dans l'URL.

Paramètres de route (route params)

Un paramètre dynamique se définit avec deux-points : dans le chemin :

1const routes = [
2  {
3    path: '/system/:id',
4    name: 'system-detail',
5    component: SystemDetail
6  },
7  {
8    path: '/crew/:name',
9    name: 'crew-detail',
10    component: CrewDetail
11  },
12  // Plusieurs paramètres
13  {
14    path: '/module/:moduleId/system/:systemId',
15    name: 'module-system',
16    component: ModuleSystem
17  }
18]

Lire les paramètres - useRoute()

Le composable useRoute() donne accès aux informations sur la route actuelle, y compris les paramètres :

1<script setup>
2import { useRoute } from 'vue-router'
3
4const route = useRoute()
5
6// Accès aux paramètres
7console.log(route.params.id) // ex. '42'
8console.log(route.path)      // ex. '/system/42'
9console.log(route.name)      // ex. 'system-detail'
10</script>
11
12<template>
13  <div>
14    <h1>Système #{{ route.params.id }}</h1>
15  </div>
16</template>
1<template>
2  <div v-for="system in systems" :key="system.id">
3    <!-- URL sous forme de chaîne -->
4    <RouterLink :to="`/system/${system.id}`">
5      {{ system.name }}
6    </RouterLink>
7
8    <!-- Notation objet (recommandée) -->
9    <RouterLink :to="{ name: 'system-detail', params: { id: system.id } }">
10      {{ system.name }}
11    </RouterLink>
12  </div>
13</template>

Réactivité aux changements de paramètres

Quand tu changes un paramètre au sein de la même route, le composant n'est PAS démonté. Utilise watch pour réagir aux changements :

1<script setup>
2import { ref, watch } from 'vue'
3import { useRoute } from 'vue-router'
4
5const route = useRoute()
6const systemData = ref(null)
7
8watch(
9  () => route.params.id,
10  (newId) => {
11    // Charger les données du nouveau système
12    loadSystem(newId)
13  },
14  { immediate: true }
15)
16</script>

Paramètres de requête (query parameters)

Les paramètres de requête sont la partie de l'URL après le caractère ? :

1<script setup>
2import { useRoute, useRouter } from 'vue-router'
3
4const route = useRoute()
5const router = useRouter()
6
7// URL : /systems?module=habitat&sort=priority
8console.log(route.query.module) // 'habitat'
9console.log(route.query.sort)   // 'priority'
10
11// Navigation avec query
12function filterByModule(module) {
13  router.push({
14    name: 'systems',
15    query: { module, sort: 'priority' }
16  })
17}
18</script>

Paramètres optionnels et validés

1const routes = [
2  // Paramètre optionnel avec ?
3  { path: '/system/:id?' },
4
5  // Regex - chiffres uniquement
6  { path: '/system/:id(\\d+)' },
7
8  // Paramètre répétable
9  { path: '/modules/:ids+' }
10]
Code de cette leçon : App.vue
1<script setup>
2import { ref } from 'vue'
3
4// Simulation des routes imbriquées
5const currentPath = ref('/mission-control')
6const sidebarItems = [
7  { path: '/mission-control', label: 'Aperçu', name: 'overview' },
8  { path: '/mission-control/systems', label: 'Systèmes', name: 'systems' },
9  { path: '/mission-control/crew', label: 'Équipage', name: 'crew' }
10]
11
12function navigate(path) {
13  currentPath.value = path
14}
15
16const isActive = (path) => currentPath.value === path
17</script>
18
19<template>
20  <div class="nova-lab">
21    <h1>NOVA LAB - Nested Routes</h1>
22
23    <div class="layout">
24      <aside class="sidebar">
25        <h3>Centre de Contrôle de Mission</h3>
26        <nav>
27          <a
28            v-for="item in sidebarItems"
29            :key="item.path"
30            @click.prevent="navigate(item.path)"
31            :class="{ active: isActive(item.path) }"
32            href="#"
33          >
34            {{ item.label }}
35          </a>
36        </nav>
37
38        <div class="config-info">
39          <pre>
40children: [
41  { path: '', component: Overview },
42  { path: 'systems', component: Systems },
43  { path: 'crew', component: Crew }
44]</pre>
45        </div>
46      </aside>
47
48      <main class="content">
49        <div v-if="currentPath === '/mission-control'" class="child-page">
50          <h2>Aperçu de la Mission</h2>
51          <p>Vue par défaut (path: '')</p>
52          <div class="stats">
53            <div class="stat">
54              <span class="label">Statut de la mission</span>
55              <span class="value ok">ACTIVE</span>
56            </div>
57            <div class="stat">
58              <span class="label">Jour de mission</span>
59              <span class="value">247</span>
60            </div>
61            <div class="stat">
62              <span class="label">Équipage</span>
63              <span class="value">12 personnes</span>
64            </div>
65          </div>
66        </div>
67
68        <div v-else-if="currentPath === '/mission-control/systems'" class="child-page">
69          <h2>Systèmes de la Base</h2>
70          <p>Child route : path: 'systems'</p>
71          <ul class="systems-list">
72            <li>Oxygen Generator - ONLINE</li>
73            <li>Water Recycler - ONLINE</li>
74            <li>Power Grid - WARNING</li>
75            <li>Communications - ONLINE</li>
76          </ul>
77        </div>
78
79        <div v-else-if="currentPath === '/mission-control/crew'" class="child-page">
80          <h2>Équipage</h2>
81          <p>Child route : path: 'crew'</p>
82          <ul class="crew-list">
83            <li>Dr. Nova - Commander</li>
84            <li>Eng. Kowalski - Systems</li>
85            <li>Dr. Chen - Science</li>
86          </ul>
87        </div>
88      </main>
89    </div>
90  </div>
91</template>
92
93<style scoped>
94.nova-lab {
95  background: #0a0e27;
96  color: #00ff88;
97  min-height: 100vh;
98  padding: 20px;
99  font-family: monospace;
100}
101h1 { color: #00ffff; margin-bottom: 15px; }
102h2 { color: #00b4d8; }
103h3 { color: #00ffff; margin-bottom: 10px; }
104p { color: #c0c0c0; }
105.layout {
106  display: grid;
107  grid-template-columns: 220px 1fr;
108  gap: 15px;
109}
110.sidebar {
111  background: rgba(0, 180, 216, 0.05);
112  border: 1px solid #1a1e37;
113  padding: 15px;
114}
115.sidebar nav { display: flex; flex-direction: column; gap: 5px; }
116.sidebar a {
117  color: #00ff88;
118  text-decoration: none;
119  padding: 8px;
120  border-left: 2px solid transparent;
121  cursor: pointer;
122}
123.sidebar a.active {
124  border-left-color: #00ffff;
125  color: #00ffff;
126  background: rgba(0, 255, 255, 0.05);
127}
128.config-info { margin-top: 15px; }
129.config-info pre {
130  font-size: 10px;
131  color: #888;
132  background: #1a1e37;
133  padding: 8px;
134}
135.content {
136  background: rgba(0, 180, 216, 0.05);
137  border: 1px solid #1a1e37;
138  padding: 15px;
139}
140.child-page { min-height: 200px; }
141.stats { display: flex; gap: 15px; margin-top: 15px; flex-wrap: wrap; }
142.stat {
143  background: #1a1e37;
144  padding: 10px 15px;
145  border: 1px solid #00b4d8;
146}
147.stat .label { display: block; color: #888; font-size: 11px; }
148.stat .value { display: block; color: #00ff88; font-size: 18px; margin-top: 4px; }
149.stat .value.ok { color: #00ff88; }
150ul { color: #c0c0c0; margin-top: 10px; }
151li { margin: 5px 0; }
152</style>

Tu as repéré une erreur dans cette leçon ?

Teste tes connaissances

Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.

  1. 1. Comment définit-on un paramètre dynamique dans un chemin Vue Router ?

  2. 2. Comment accède-t-on aux paramètres de la route actuelle dans la Composition API ?

Voici 2 des 3 questions de cette leçon. Réponds aux autres dans le jeu.

Tâches pratiques dans le jeu

  • Éditeur de code

    Crée une route /system/:id et un composant qui lit params.id via useRoute().

  • Tri vertical

    Ordonne les étapes de traitement d'une route dynamique :

  • Clique dans l'ordre

    Ordonne la navigation programmatique avec des paramètres :

  • Éditeur de code

    Navigue avec des query params et lis-les dans un composant via useRoute().query.

  • Tri horizontal

    Ordonne la syntaxe de RouterLink avec un paramètre dynamique :