Navigation entre les routes

Dans ce chapitre, vous apprendrez à utiliser Vue Router pour mettre en œuvre la navigation entre pages avec séparation front-end/back-end, y compris les paramètres de route dynamiques.


Pourquoi utiliser le routage ?

Les sites web multi-pages traditionnels demandent un nouveau fichier HTML au serveur lorsque vous cliquez sur un lien, ce qui provoque un rafraîchissement complet de la page avec un scintillement d'écran blanc.

Ce que Vue Router implémente, c'estle routage côté front-end: lorsque l'URL change, aucune requête n'est envoyée au serveur ; à la place, JS change dynamiquement le composant affiché.

Avantages de cette approche :Changement de page sans rafraîchissement, offrant une expérience fluide comme une application native。


Concepts clés de Vue Router

ConceptObjectifCode correspondant
Table de routageDéfinit la correspondance entre les chemins d'URL et les composantsroutesTableau
Point de sortie du routeurL'emplacement où le composant correspondant est affiché<RouterView />
Lien de navigationCliquez pour naviguer vers la route spécifiée<RouterLink to="...">
Routage dynamiqueL’URL contient des variables (par exemple, ID d’article)/post/:id

Installation et configuration

Si vous avez déjà sélectionné Router lors de la création du projet, vous pouvez ignorer l’étape d’installation.

Si vous ne l’avez pas sélectionné, exécutez ceci dans le terminal :

$ npm install vue-router@4

Créez le fichier de configuration des routes

Exemple

// Chemin du fichier : src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'

// Table de routes : chaque enregistrement associe un chemin à un composant
const routes = [
  {
    path: '/',                // chemin de l’URL
    name: 'home',             // Nom de la route (facultatif, utilisé dans la navigation programmatique)
    component: HomeView       // Composant de page correspondant
  },
  {
    // Route dynamique : :id est un espace réservé qui correspond à n’importe quelle valeur
    // /post/1, /post/2, /post/hello correspondront tous à cette entrée
    path: '/post/:id',
    name: 'post',
    // Chargement différé : chargé uniquement lors de l'accès ; l'empaquetage extrait un fichier JS distinct
    component: () => import('../views/PostView.vue')
  }
]

// Créer l'instance du routeur
const router = createRouter({
  history: createWebHistory(),  // Utiliser le mode History HTML5 (l'URL ressemble à un chemin normal)
  routes                         // Enregistrer la table des routes
})

export default router

Différences entre les deux modes de routeur :createWebHistoryProduit des URL propres (/post/1), nécessite la prise en charge de la configuration du serveur. Si l'environnement de déploiement est incertain, vous pouvez utilisercreateWebHashHistory, où l'URL contient un symbole # (/#/post/1), aucune configuration serveur nécessaire.

Enregistrer le routeur dans main.js

Exemple

<!-- Chemin du fichier : src/App.vue -->
<script setup>
import NavBar from './components/NavBar.vue'
</script>

<template>
  <NavBar />
  <main>
<!-- RouterView est l'endroit magique : le composant correspondant à la route actuelle sera rendu ici -->
    <RouterView />
  </main>
</template>

RouterViewest la sortie centrale du système de routage.

Lorsque l'URL est/, il affiche HomeView ; lorsque l'URL est/post/1, il affiche PostView.


RouterLink — Navigation déclarative

RouterLinkest un composant de navigation fourni par Vue Router, remplaçant la balise traditionnelle<a>balise.

Il ne déclenche pas de rafraîchissement de page ; il ne fait que changer le composant affiché via JS.

Exemple

<template>
  <!-- Syntaxe normale -->
  <RouterLink to="/">Home</RouterLink>

  <!-- Syntaxe de route nommée (recommandé : un seul endroit à modifier lorsque le chemin change) -->
  <RouterLink :to="{ name: 'post', params: { id: article.id } }">
Lire l’article {{ article.id }}
  </RouterLink>

  <!-- La balise a traditionnelle provoque un rafraîchissement de page, ne pas utiliser -->
  <!-- <a href="/post/1">Lire l’article complet</a> -->
</template>

useRoute — Lecture des paramètres de route

Dans la page de détail PostView, vous devez connaître l’ID de l’article dans l’URL pour trouver l’article correspondant.

useRoutesert à lire les informations sur la route actuelle.

Exemple

<!-- Chemin du fichier : src/views/PostView.vue -->
<script setup>
import { useRoute } from 'vue-router'

// useRoute renvoie l’objet route actuel
const route = useRoute()

// route.params contient les paramètres de l’URL
// Par exemple, si l’URL est /post/3, alors route.params.id === '3'
console.log('Article ID:', route.params.id)
</script>

<template>
  <div>
    <h1>Page de détail de l'article</h1>
    <!-- Remarque : les valeurs dans params sont toutes des chaînes de caractères -->
    <p>ID de l’article actuel : {{ route.params.id }}</p>
  </div>
</template>

route.params.idla valeur est toujours une chaîne. Même si l’URL est/post/3, la valeur récupérée est'3'pas un nombre3. Lorsqu’un nombre est nécessaire, utilisezNumber(route.params.id)ouparseIntpour convertir.


Exercice pratique : Compléter la page de détail de l’article

Rendre BlogCard cliquable pour la navigation, et la page de détail affiche le contenu complet de l'article en fonction de l'ID.

Étape 1 : Modifier BlogCard pour prendre en charge la navigation au clic

Exemple

<!-- Chemin du fichier : src/components/BlogCard.vue -->
<script setup>
defineProps({
id: Number, // Nouveau : ID de l'article pour la navigation
  title: String,
  summary: String,
  date: String,
  category: String
})
</script>

<template>
  <!-- Toute la carte est enveloppée dans RouterLink, donc cliquer n'importe où déclenche la navigation -->
  <RouterLink :to="{ name: 'post', params: { id } }" class="card-link">
    <div class="card">
      <span class="tag">{{ category }}</span>
      <h3>{{ title }}</h3>
      <p>{{ summary }}</p>
      <span class="date">{{ date }}</span>
    </div>
  </RouterLink>
</template>

<style scoped>
.card-link { text-decoration: none; color: inherit; display: block; }
.card {
  background: #fff;
  border-radius: 12px;
  padding: 20px;
  box-shadow: 0 2px 12px rgba(0,0,0,0.08);
  transition: transform 0.2s, box-shadow 0.2s;
}
.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 24px rgba(0,0,0,0.12);
}
.tag {
  display: inline-block;
  padding: 2px 10px;
  background: #E8EEF5;
  color: #427DB8;
  border-radius: 12px;
  font-size: 12px;
}
.card h3 { margin: 10px 0 8px; font-size: 18px; }
.card p { color: #666; font-size: 14px; line-height: 1.6; }
.date { font-size: 12px; color: #999; }
</style>

Étape 2 : Créer la page de détail PostView

La page de détail lit l'ID à partir de l'URL, puis trouve et affiche l'article correspondant à partir des données d'articles.

Exemple

<!-- Chemin du fichier : src/views/PostView.vue -->
<script setup>
import { ref, computed } from 'vue'
import { useRoute, RouterLink } from 'vue-router'

const route = useRoute()
const id = Number(route.params.id)

// Toutes les données d'articles (seront extraites dans un module partagé dans les chapitres suivants)
const articles = ref([
  {
    id: 1,
title: 'Le guide complet pour bien démarrer avec Vue3',
summary: 'Apprendre l'API Composition de Vue3 à partir de zéro',
    category: 'Vue',
    date: '2024-05-10',
    content: `
      <h2>Pourquoi apprendre Vue3 ?</h2>
      <p>Vue3 est l'un des frameworks front-end les plus populaires aujourd'hui ; il est facile à apprendre, flexible et offre d'excellentes performances.</p>
      <h2>Avantages de la Composition API</h2>
      <p>Par rapport à l'Options API de Vue2, la Composition API simplifie la réutilisation de la logique et rend l'organisation du code plus flexible.</p>
      <h2>ref et reactive</h2>
      <p>ref convient aux données de type primitif, tandis que reactive convient aux objets et aux tableaux. Cependant, en développement réel, il est recommandé d'utiliser systématiquement ref.</p>
    `
  },
  {
    id: 2,
title: 'Explication détaillée de la programmation asynchrone en JS',
summary: 'Comprendre Promise et async/await',
    category: 'JavaScript',
    date: '2024-05-08',
    content: `
      <h2>Qu'est-ce que l'asynchrone ?</h2>
      <p>JS est mono-thread ; les opérations asynchrones permettent au thread principal de ne pas se bloquer pendant le traitement de tâches telles que les requêtes réseau et les minuteurs.</p>
      <h2>Concepts clés de Promise</h2>
      <p>Promise a trois états : pending (en cours), fulfilled (réussi), rejected (échoué).</p>
    `
  }
])

// Trouver l’article par ID
const article = computed(() => {
  return articles.value.find(a => a.id === id)
})
</script>

<template>
  <div class="post-view">
    <!-- Article introuvable -->
    <div v-if="!article" class="not-found">
      <h2>Article introuvable</h2>
      <p>Article avec l'ID {{ id }} introuvable</p>
      <RouterLink to="/">Retour à l'accueil</RouterLink>
    </div>

    <!-- L'article existe, afficher le contenu complet -->
    <article v-else>
      <span class="category-tag">{{ article.category }}</span>
      <h1>{{ article.title }}</h1>
      <time>{{ article.date }}</time>
      <!-- v-html affiche les chaînes HTML -->
      <div class="content" v-html="article.content"></div>
      <RouterLink to="/" class="back-link">← Retour à l'accueil</RouterLink>
    </article>
  </div>
</template>

<style scoped>
.post-view {
  max-width: 720px;
  margin: 40px auto;
  padding: 0 20px;
}

.category-tag {
  display: inline-block;
  padding: 4px 12px;
  background: #E8EEF5;
  color: #427DB8;
  border-radius: 12px;
  font-size: 13px;
  margin-bottom: 12px;
}

h1 {
  font-size: 32px;
  margin-bottom: 12px;
  line-height: 1.4;
}

time {
  display: block;
  color: #999;
  font-size: 14px;
  margin-bottom: 30px;
}

.content {
  line-height: 1.8;
  font-size: 16px;
  color: #333;
}

.content :deep(h2) {
  margin: 24px 0 12px;
  font-size: 22px;
}

.content :deep(p) {
  margin-bottom: 12px;
}

.back-link {
  display: inline-block;
  margin-top: 40px;
  color: #427DB8;
  text-decoration: none;
}

.not-found {
  text-align: center;
  padding: 60px 0;
}
</style>

v-htmlest utilisé pour afficher des chaînes HTML, mais attention : ne l'utilisez pas pour afficher des entrées utilisateur, sinon il y a un risque de sécurité XSS. Le contenu des articles ici est écrit par les développeurs eux-mêmes, donc c'est sûr.


Résumé du chapitre

Dans ce chapitre, vous avez appris l'utilisation essentielle de Vue Router : configuration de la table de routes (le chemin correspond au composant), navigation avec RouterLink, emplacement RouterView, routes dynamiques /post/:id, et useRoute pour lire les paramètres de route.

Maintenant, le blog offre une véritable expérience multi-pages — parcourez la liste sur la page d'accueil, cliquez pour accéder à la page de détail et lire le contenu complet.

Autres extensions