Routennavigation

In diesem Kapitel lernst du, Vue Router zu verwenden, um Seitennavigation mit Frontend-/Backend-Trennung zu implementieren, einschließlich dynamischer Routenparameter.


Warum Routing verwenden?

Traditionelle Multi-Page-Websites fordern beim Klick auf einen Link eine neue HTML-Datei vom Server an, wodurch die gesamte Seite neu geladen wird und ein Weißbild-Flackern entsteht.

Was Vue Router implementiert, istFrontend-Routing: Wenn sich die URL ändert, wird keine Anfrage an den Server gesendet; stattdessen schaltet JS die angezeigte Komponente dynamisch um.

Vorteile dieses Ansatzes:Seitenwechsel ohne Neuladen, was ein flüssiges Erlebnis wie bei einer nativen App bietet。


Vue Router Kernkonzepte

KonzeptZweckEntsprechender Code
RoutentabelleDefiniert die Zuordnung zwischen URL-Pfaden und KomponentenroutesArray
Router-OutletDie Stelle, an der die passende Komponente angezeigt wird<RouterView />
NavigationslinkKlicken, um zur angegebenen Route zu navigieren<RouterLink to="...">
Dynamisches RoutingURL enthält Variablen (z. B. Artikel-ID)/post/:id

Installation und Konfiguration

Wenn du bei der Erstellung des Projekts bereits Router ausgewählt hast, kannst du den Installationsschritt überspringen.

Wenn du ihn nicht ausgewählt hast, führe Folgendes im Terminal aus:

$ npm install vue-router@4

Erstelle die Routenkonfigurationsdatei

Beispiel

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

// Routentabelle: jeder Eintrag ordnet einen Pfad einer Komponente zu
const routes = [
  {
    path: '/',                // URL-Pfad
    name: 'home',             // Routenname (optional, wird bei programmatischer Navigation verwendet)
    component: HomeView       // Zugehörige Seitenkomponente
  },
  {
    // Dynamische Route: :id ist ein Platzhalter, der auf jeden beliebigen Wert passt
    // /post/1, /post/2, /post/hello werden alle mit diesem Eintrag übereinstimmen
    path: '/post/:id',
    name: 'post',
    // Lazy Loading: wird nur beim Zugriff geladen; beim Bundling wird eine separate JS-Datei herausgetrennt
    component: () => import('../views/PostView.vue')
  }
]

// Router-Instanz erstellen
const router = createRouter({
  history: createWebHistory(),  // HTML5-History-Modus verwenden (URL sieht wie ein normaler Pfad aus)
  routes                         // Routentabelle registrieren
})

export default router

Unterschiede zwischen den beiden Router-Modi:createWebHistoryErzeugt saubere URLs (/post/1), erfordert Unterstützung durch die Serverkonfiguration. Wenn die Deployment-Umgebung unsicher ist, kannst ducreateWebHashHistory verwenden, wobei die URL ein #-Symbol enthält (/#/post/1) und keine Serverkonfiguration erforderlich ist.

Router in main.js registrieren

Beispiel

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

<template>
  <NavBar />
  <main>
<!-- RouterView ist der magische Ort: Die Komponente, die der aktuellen Route entspricht, wird hier gerendert -->
    <RouterView />
  </main>
</template>

RouterViewist der zentrale Ausgang des Routing-Systems.

Wenn die URL/, wird HomeView gerendert; wenn die URL/post/1, wird PostView gerendert.


RouterLink — Deklarative Navigation

RouterLinkist eine von Vue Router bereitgestellte Navigationskomponente und ersetzt das Traditionelle<a>-Tag anzeigen können.

Es löst keinen Seiten-Refresh aus; es wechselt nur die angezeigte Komponente über JS.

Beispiel

<template>
  <!-- Normale Syntax -->
  <RouterLink to="/">Startseite</RouterLink>

  <!-- Syntax für benannte Routen (empfohlen: nur eine Stelle zu ändern, wenn sich der Pfad ändert) -->
  <RouterLink :to="{ name: 'post', params: { id: article.id } }">
Artikel lesen {{ article.id }}
  </RouterLink>

  <!-- Traditionelles a-Tag verursacht Seiten-Neuladen, nicht verwenden -->
  <!-- <a href="/post/1">Ganzen Artikel lesen</a> -->
</template>

useRoute — Routenparameter lesen

Auf der Detailseite PostView musst du die Artikel-ID in der URL kennen, um den entsprechenden Artikel zu finden.

useRoutewird verwendet, um die aktuellen Routeninformationen zu lesen.

Beispiel

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

// useRoute gibt das aktuelle Routenobjekt zurück
const route = useRoute()

// route.params enthält die Parameter in der URL
// Zum Beispiel, wenn die URL /post/3 ist, dann ist route.params.id === '3'
console.log('Artikel-ID:', route.params.id)
</script>

<template>
  <div>
    <h1>Artikelseite</h1>
    <!-- Hinweis: Werte in params sind alle Zeichenketten -->
    <p>Aktuelle Artikel-ID: {{ route.params.id }}</p>
  </div>
</template>

route.params.idDer Wert ist immer eine Zeichenkette. Selbst wenn die URL/post/3, der abgerufene Wert ist'3'keine Zahl3. Wenn eine Zahl benötigt wird, verwendeNumber(route.params.id)oderparseIntum zu konvertieren.


Praktische Übung: Artikeldetailseite vervollständigen

BlogCard für die Navigation anklickbar machen und die Detailseite zeigt den vollständigen Artikelinhalt anhand der ID an.

Schritt 1: BlogCard für Klick-Navigation anpassen

Beispiel

<!-- Dateipfad: src/components/BlogCard.vue -->
<script setup>
defineProps({
id: Number, // Neu: Artikel-ID für Navigation
  title: String,
  summary: String,
  date: String,
  category: String
})
</script>

<template>
  <!-- Die gesamte Karte ist in RouterLink eingebettet, sodass ein Klick an beliebiger Stelle navigiert -->
  <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>

Schritt 2: PostView-Detailseite erstellen

Die Detailseite liest die ID aus der URL und findet dann den entsprechenden Artikel aus den Artikeldaten und zeigt ihn an.

Beispiel

<!-- Dateipfad: 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)

// Alle Artikeldaten (werden in späteren Kapiteln in ein gemeinsames Modul ausgelagert)
const articles = ref([
  {
    id: 1,
title: 'Der vollständige Leitfaden für den Einstieg in Vue3',
summary: 'Vue3 Composition API von Grund auf lernen',
    category: 'Vue',
    date: '2024-05-10',
    content: `
      <h2>Warum Vue3 lernen?</h2>
      <p>Vue3 ist heute eines der beliebtesten Frontend-Frameworks; es ist einfach zu lernen, flexibel und leistungsstark.</p>
      <h2>Vorteile der Composition API</h2>
      <p>Verglichen mit der Options API von Vue2 macht die Composition API die Wiederverwendung von Logik einfach und die Codeorganisation flexibler.</p>
      <h2>ref und reactive</h2>
      <p>ref eignet sich für Daten primitiver Typen, während reactive sich für Objekte und Arrays eignet. In der realen Entwicklung wird jedoch empfohlen, konsequent ref zu verwenden.</p>
    `
  },
  {
    id: 2,
title: 'Detaillierte Erklärung der JS-Async-Programmierung',
summary: 'Promise und async/await verstehen',
    category: 'JavaScript',
    date: '2024-05-08',
    content: `
      <h2>Was ist asynchron?</h2>
      <p>JS ist single-threaded; asynchrone Vorgänge sorgen dafür, dass der Hauptthread bei der Bearbeitung von Aufgaben wie Netzwerkanfragen und Timern nicht blockiert.</p>
      <h2>Kernkonzepte von Promise</h2>
      <p>Promise hat drei Zustände: pending (in Bearbeitung), fulfilled (erfolgreich), rejected (fehlgeschlagen).</p>
    `
  }
])

// Artikel anhand der ID finden
const article = computed(() => {
  return articles.value.find(a => a.id === id)
})
</script>

<template>
  <div class="post-view">
    <!-- Artikel nicht gefunden -->
    <div v-if="!article" class="not-found">
      <h2>Artikel nicht gefunden</h2>
      <p>Artikel mit ID {{ id }} nicht gefunden</p>
      <RouterLink to="/">Zurück zur Startseite</RouterLink>
    </div>

    <!-- Artikel vorhanden, vollständigen Inhalt anzeigen -->
    <article v-else>
      <span class="category-tag">{{ article.category }}</span>
      <h1>{{ article.title }}</h1>
      <time>{{ article.date }}</time>
      <!-- v-html rendert HTML-Zeichenfolgen -->
      <div class="content" v-html="article.content"></div>
      <RouterLink to="/" class="back-link">← Zurück zur Startseite</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-htmlwird verwendet, um HTML-Strings zu rendern, aber Vorsicht: Verwende es nicht, um Benutzereingaben zu rendern, andernfalls besteht ein XSS-Sicherheitsrisiko. Die Artikelinhalte hier werden von Entwicklern selbst geschrieben, daher ist es sicher.


Kapitelzusammenfassung

In diesem Kapitel hast du die Kernverwendung von Vue Router kennengelernt: Routentabellenkonfiguration (Pfad wird auf Komponente abgebildet), RouterLink-Navigation, RouterView-Outlet, dynamische Routen /post/:id und useRoute zum Auslesen von Routenparametern.

Jetzt hat der Blog ein echtes Multi-Page-Erlebnis – durchstöbere die Liste auf der Startseite, klicke, um zur Detailseite zu gelangen und den vollständigen Inhalt zu lesen.

Weitere Erweiterungen