Vue.js unter der Lupe, Teil 3: Vue Router

Vue.js unter der Lupe: Der Vue Router
Keine Kommentare

In dieser Tutorial-Reihe nehmen wir das JavaScript-Framework Vue.js genau unter die Lupe. Nach dem Blick auf das State Management mit der Bibliothek VueX schauen wir uns jetzt den Vue Router an: Einen zentralen Bestandteil jeder Vue-Anwendung.

In JavaScript-Web-Apps ist der Router dafür verantwortlich, dass die aktuelle, angezeigte Ansicht mit dem Inhalt der Browser-Adresszeile synchronisiert wird. Mit anderen Worten, handelt es sich also um den Teil, der für die Veränderung der URL zuständig ist, wenn man etwas auf einer Seite anklickt und der dabei hilft, die richtige Ansicht anzuzeigen, wenn man eine bestimmte URL aufruft. Das Web ist traditionell rund um URLs herum aufgebaut. Ruft man eine bestimmte URL auf, wird eine spezifische Seite angezeigt.

Mit der Einführung von Applikationen, die innerhalb des Browsers ausgeführt werden und die Ansicht des Users verändern, funktionierte diese Interaktion in vielen der Apps nicht mehr. Die URLs mussten manuell über das History API  im Browser aktualisiert werden. Ein Router wird benötigt, wenn man eine URL mit der View einer App synchronisieren muss. Das ist häufig nötig und alle größeren Frameworks bieten mittlerweile die Möglichkeit an, Routen zu managen.

Die Bibliothek Vue Router ist die richtige Wahl für Vue.js-Anwendungen. Vue erzwingt die Verwendung von dieser Bibliothek nicht. Sie können jede beliebige generische Routing-Bibliothek verwenden oder auch Ihre eigene Integration des History APIs erstellen. Der Vorteil der Verwendung des Vue Routers ist aber, dass er die offizielle Lösung ist.

Lesen Sie auch: Vue im Vergleich: Wie man eine Vue-Komponente baut und wann man lieber Angular oder React nimmt

Das wiederum bedeutet, dass er von denselben Menschen gewartet wird, die für Vue.js zuständig sind. Somit hat man eine konsistentere Integration in das Framework. Es bedeutet ebenfalls, dass die Komptabilität in jedem Fall auch in der Zukunft gewährleistet ist.

Die Installation

Der Vue-Router ist über das npm-Package vue-router erhältlich.

Setzt man Vue über ein Script-Tag ein, kann man den Vue Router mit einbinden, indem man folgendes benutzt:

<script src="https://unpkg.com/vue-router"></script>

(Bei unpkg.com handelt es sich um ein sehr praktisches Tool, dass jedes npm-Package mit einem simplen Link im Browser verfügbar macht.)

Wenn man das Vue CLI benutzt, so installiert man den Vue Router mit:

npm install vue-router

Sobald man also vue-router installiert hat und entweder mit einem Skript oder dem Vue CLI erhältlich gemacht hat, kann man ihn jetzt in die eigene Applikation importieren.

Der Import erfolgt nach vue und man ruft Vue.use(VueRouter) für die Installation innerhalb der Applikation auf:

import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)

Nachdem man Vue.use() aufruft und das Router-Objekt übergibt, hat man Zugriff auf diese Objekte in jeder Komponente der Applikation:

  • this.$router  ist das Router-Objekt
  • this.$route  ist das aktuelle Route-Objekt

Das Router-Objekt

Wenn der Vue Router in der Vue-Root-Komponente installiert ist, erhält man mit this.$router von jeder Komponente aus Zugriff auf das Router-Objekt, das viele tolle Features mitbringt:

Wir können die Applikation zu einer neuen Route navigieren lassen, indem wir folgendes benutzten:

  • this.$router.push()
  • this.$router.replace()
  • this.$router.go()

Diese ähneln den Methoden pushState, replaceState und go des History APIs.

push() wird benutzt, um eine neue Route zu öffnen und dem Browserverlauf ein neues Item hinzuzufügen. replace() macht das gleiche, fügt dem Browserverlauf aber keinen neuen Zustand hinzu.

Anwendungsbeispiele:

this.$router.push('about') //named route, see later
this.$router.push({ path: 'about' })
this.$router.push({ path: 'post', query: { post_slug: 'hello-world' } }) //using query par
ameters (post?post_slug=hello-world)
this.$router.replace({ path: 'about' })

Hierbei geht go() vor und zurück und akzeptiert eine Zahl, die entweder positiv oder negativ sein kann, um im Verlauf zurückzugehen.

this.$router.go(-1) //go back 1 step
this.$router.go(1) //go forward 1 step

Die Routen definieren

Ich benutze eine Vue Single File Component in diesem Beispiel. Im Template verwende ich einen nav-Tag, der drei router-link-Komponenten hat (Home, Login, About), die über ein Label und eine URL verfügen, die über das Attribut go zugewiesene wird.

Die router-view-Komponente befindet sich dort, wo der Vue Router den Inhalt ablegt, der zur aktuellen URL passt.

<template>
<div id="app">
<nav>
<router-link to="/">Home</router-link>
<router-link to="/login">Login</router-link>
<router-link to="/about">About</router-link>
</nav>
<router-view></router-view>
</div>
</template>

Eine router-link-Komponente rendert standardmäßig einen a-tag (das kann geändert werden). Jedes Mal, wenn sich die Route  entweder durch das Anklicken eines Links oder dem Verändern der URL verändert, wird dem Element eine router-active-link-Klasse hinzugefügt, dass auf die aktive Route referiert und sie gestaltbar macht.

Im JavaScript-Teil wird zuerst der Router eingebunden und installiert, dann definiert man 3 Routen-Komponenten.

Diese werden an die Initialisierung des router-Objekts übergeben und dieses Objekt wird an die Vue-Root-Instanz weitergegeben.

Hier ist der Code dafür:

<script>
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(Router)
const Home = {
template: '<div>Home</div>'
Vue Router
115
}
const Login = {
template: '<div>Login</div>'
}
const About = {
template: '<div>About</div>'
}
const router = new VueRouter({
routes: [
{ path: '/', component: Home },
{ path: '/login', component: Login },
{ path: '/about', component: About }
]
})
new Vue({
router
}).$mount('#app')
</script>

In einer Vue-Applikation instanziieren und mounten Sie die Root-Applikation, indem Sie folgendes benutzen:

new Vue({
render: h => h(App)
}).$mount('#app')

Wenn der Vue Router verwendet wird, dann übergibt man keine render -Eigenschaft, stattdessen verwendet man router.

Die im obigen Beispiel verwendete Syntax

new Vue({
router
}).$mount('#app')

ist eine Kurzform für:

new Vue({
router: router
}).$mount('#app')

Im Beispiel übergeben wir ein routes-Array an den VueRouter-Constructor. Jede Route in diesem Array hat einen path– und einen component-Parameter.

Wenn Sie auch einen name-Parameter übergeben, haben Sie eine named Route.

Named Routes nutzen, um Parameter an die Router push- und replace-Methode zu übergeben

Erinnern Sie sich noch daran, wie wir das Router-Objekt benutzt haben, um einen neuen Zustand zu pushen?

this.$router.push({ path: 'about' })

Mit einer named Route kann man Parameter an die neue Route übergeben:

this.$router.push({ name: 'post', params: { post_slug: 'hello-world' } })

Das gleiche gilt für replace()

this.$router.replace({ name: 'post', params: { post_slug: 'hello-world' } })

Wenn ein Benutzer router-link anklickt, rendert die Applikation die die Route-Komponente, die der an den Link übergebenen URL entspricht. Die neue Route-Komponente, die die URL handlet, wird instanziiert und ihre Guards aufgerufen. Die alte Route-Komponente wird zerstört.

Routen-Guards

Da wir die Guards erwähnt haben, gehen wir darauf auch ein.

Sie können sich Guads am ehesten als Lifecycle-Hooks oder Middleware vorstellen. Das sind Funktionen, die zu bestimmten Zeiten während der Ausführung der Applikation aufgerufen werden können. Sie können einspringen und die Ausführung einer Route ändern, die Anfrage umleiten oder einfach abbrechen.

Sie können globale Guards haben, indem Sie den beforeEach()– und afterEach()-Eigenschaften des Routers einen Callback hinzufügen.

  • beforeEach() wird aufgerufen, bevor die Navigation bestätigt ist
  • beforeResolve() wird aufgerufen, wenn beforeEach ausgeführt wird und alle Guards der Komponenten beforeRouterEnter und beforeRouteUpdate aufgerufen werden, aber bevor die Navigation bestätigt ist. Die letzte Überprüfung, wenn man es so sehen möchte
  • afterEach() wird aufgerufen, nachdem die Navigation bestätigt wurde.

Aber was genau heißt es eigentlich, wenn „die Navigation bestätigt wurde“? Das sehen wir gleich. In der Zwischenzeit können Sie es als „die Applikation kann diese Route nehmen“ betrachten.

Die Verwendung sieht folgendermaßen aus:

this.$router.beforeEach((to, from, next) => {
// ...
})
this.$router.afterEach((to, from) => {
// ...
})

Hier repräsentieren to und from die Routenobjekte, zu denen wir hin- und von denen wir weggehen. beforeEach hat einen zusätzlichen Parameter next, der die Navigation blockiert und sie unbestätigt lässt, wenn er mit false als Parameter aufgerufen wird. Wenn sie mit Node-Middelware vertraut sind: Dort ist es genau so. next() sollte immer aufgerufen werden, da ansonsten die Ausführung hängen bleibt.

Einzelne Routenkomponenten besitzen ebenfalls Guards:

  • beforeRouteEnter(from, to, next) wird aufgerufen, bevor die derzeitige Route bestätigt ist
  • beforeRouteUpdate(from, to, next) wird aufgerufen, wenn die Route sich verändert, aber die Komponente, die sie steuert noch dieselbe ist (mit dynamischen Routing, siehe unten)
  • beforeRouteLeave(from, to, next) wird aufgerufen, wenn man sich von hier wegbewegt

Wir haben die Navigation erwähnt. Um festzustellen, ob die Navigation zu einer Route bestätigt wird, führt der Vue Router einige Prüfungen durch:

    • er ruft den beforeRouteLeave-Guard der aktuellen Komponente(n) auf
    • er ruft den Router beforeEach()-Guard auf
    • er ruft beforeRouteUpdate() in allen Komponenten auf, die wiederverwendet werden müssen, wenn solche existieren
    • er ruft den beforeEnter()-Guard auf dem Routenobjekt auf (das wurde nicht erwähnt, ist aber hier nachzusehen)
    • er ruft beforeRouterEnter() in der Komponente auf, die wir betreten sollten
    • er ruft den Router beforeResolve()-Guard auf
    • wenn alles in Ordnung ist, dann wird die Navigation bestätigt!
    • er ruft den afterEach()-Guard auf

Sie können routerspezifische Guards (beforeRouteEnter und beforeRouteUpdate, im Fall von dynamischen Routing) als LifeCycle-Hooks einsetzen. So kann z. B. man Data Fetching Requests starten.

Dynamisches Routing

Das obige Beispiel zeigt eine andere View auf Basis der URL und wie die /, /login and /about Routen verwaltet werden.
Häufig müssen dynamische Routen verwaltet werden, z. B. alle Beiträge unter /post/ zu haben, jeden mit dem Slug-Namen:

  • /post/first
  • /post/another-post
  • /post/hello-world

Das können Sie mit einem dynamischen Segment erreichen.

Das hier sind statische Segmente:

const router = new VueRouter({
routes: [
{ path: '/', component: Home },
{ path: '/login', component: Login },
{ path: '/about', component: About }
]
})

Wir fügen ein dynamisches Segment hinzu, um Blog-Posts handhaben zu können:

const router = new VueRouter({
routes: [
{ path: '/', component: Home },
{ path: '/post/:post_slug', component: Post },
{ path: '/login', component: Login },
{ path: '/about', component: About }
]
})

Beachte Sie die :posts_slug-Syntax. Das bedeutet, dass Sie jeden belieben String benutzen können, und dass die Strings dann auf dempost_slug abgebildet werden.

Sie sind allerdings nicht auf diese Art der Syntax eingeschränkt. Vue verlässt sich auf diese Bibliothek, um dynamische Routen zu analysieren und Sie können sich mit der Hilfe von Regular Expressions (Reguläre Ausdrücke) nach Herzenslust austoben.

Nun können wir in der Route-Komponente für Posts die Route mit $route und den Post-Slug mit $route.params.post_slug referenzieren:

const Post = {
template: '<div>Post: {{ $route.params.post_slug }}</div>'
}

Jetzt können wir diesen Parameter benutzen, um den Inhalt aus dem Backend laden zu können.

Sie können so viele dynamische Segmente in der gleichen URL haben, wie Sie wollen:

/post/:author/:post_slug

Sie erinnern sich noch daran, wie wir zuvor darüber sprachen, was passiert, wenn ein Benutzer zu einer neuen Ansicht navigiert?

Im Fall der dynamischen Routen verhält es sich etwas anders.

Um effizienter zu sein, zerstört Vue nicht etwa die aktuellen Routenkomponenten und führt eine Re-Instanziierung durch. Stattdessen wird die aktuelle Instanz wiederverwendet.

Wenn das passiert, ruft Vue das beforeRouteUpdate-Lifecyle-Ereignis auf. Dort können Sie dann alle Arbeiten vollbringen, die Sie benötigen.

const Post = {
template: '<div>Post: {{ $route.params.post_slug }}</div>'
beforeRouteUpdate(to, from, next) {
console.log(`Updating slug from ${from} to ${to}`)
next() //make sure you always call next()
}
}

Props einsetzen

In den Beispielen setzte ich $route.params.* ein, um auf die Route Data zuzugreifen. Eine Komponente sollte nicht so dicht mit dem Router verbunden sein. Wir benutzen stattdessen Props:

 const Post = {
props: ['post_slug'],
template: '<div>Post: {{ post_slug }}</div>'
}
const router = new VueRouter({
routes: [
{ path: '/post/:post_slug', component: Post, props: true }
]
})

Richten Sie ihre Aufmerksamkeit darauf, dass props: true dem Routenobjekt übergeben wurde, um diese Funktionalität zu ermöglichen.

Nested Routes

Bevor ich erwähnt hatte, dass Sie so viele dynamische Segmente in der gleichen URL haben können wie Sie möchten, wie etwa hiermit:

/post/:author/:post_slug

Gehen wir davon aus, dass wir eine Autorenkomponente besitzen, die sich um die ersten dynamischen Segmente kümmert:

<template>
<div id="app">
<router-view></router-view>
</div>
</template>
<script>
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(Router)
const Author = {
template: '<div>Author: {{ $route.params.author}}</div>'
}
const router = new VueRouter({
routes: [
{ path: '/post/:author', component: Author }
]
})
new Vue({
router
}).$mount('#app')
</script>

Wir können eine zweite router-view-Komponenteninstanz in die das Template für Autoren einfügen:

const Author = {
template: '<div>Author: {{ $route.params.author}}<router-view></router-view></div>'
}

Wir fügen jetzt die Post-Komponente hinzu:

const Post = {
template: '<div>Post: {{ $route.params.post_slug }}</div>'
}

Dann injizieren wir die innere Routendynamik in die Vue Router-Konfiguration:

const router = new VueRouter({
routes: [{
path: '/post/:author',
component: Author,
children: [
path: ':post_slug',
component: Post
]
}]
})

Dieser Artikel erschien zuerst im Vue Handbook von Flavio Copes.

Unsere Redaktion empfiehlt:

Relevante Beiträge

X
- Gib Deinen Standort ein -
- or -