如何使用Vue Router,這是Vue應用程式中必不可少的一部分之一

簡介

在JavaScript網頁應用程式中,路由器是將目前顯示的視圖與瀏覽器地址欄內容同步的部分。

換句話說,它是當你在頁面上點擊某個元素時,使URL改變並顯示正確視圖的部分。

傳統上,網頁是基於URL構建的。當你訪問特定的URL時,會顯示特定的頁面。

隨著在瀏覽器內運行並改變使用者所見的應用程式的引入,許多應用程式打破了這種交互方式,你必須手動使用瀏覽器的History API更新URL。

當你需要將URL與應用程式中的視圖同步時,你就需要一個路由器。這是一個非常常見的需求,現代的主要框架現在都允許你進行路由管理。

Vue Router庫是Vue.js應用程式開發時的首選。Vue並不強制使用這個庫。你可以使用任何通用的路由庫,或者自己創建和History API集成,但是使用Vue Router的好處是它是官方的。

這意味著它是由維護Vue的同一群人維護的,所以你可以在框架中得到更一致的整合,並且保證它將始終與未來的版本兼容,無論是什麼版本。

安裝

Vue Router可以通過npmvue-router包來獲取。

如果你使用script標籤引入Vue,可以使用以下方式引入Vue Router。

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

unpkg.com是一個非常方便的工具,可以通過一個簡單的鏈接在瀏覽器中提供每個npm包

如果你使用Vue CLI,可以使用以下方式安裝

npm install vue-router

一旦你安裝了vue-router並使其可用,可以在你的應用程序中導入它。

你需要在vue之後導入它,並調用Vue.use(VueRouter)將其安裝在應用程序中。

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

在調用Vue.use()並傳遞路由器對象之後,在應用程式的任何組件中都可以訪問這些對象:

  • this.$router是路由器對象
  • this.$route是當前路由對象

路由器對象

當在將Vue Router安裝到根Vue組件時,可以使用this.$router從任何組件中訪問路由器對象,它提供了許多不錯的功能。

我們可以使用以下方法導航至新路由:

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

這類似於History API的pushStatereplaceStatego方法。

push()用於切換到新的路由,將新項目添加到瀏覽器的歷史記錄中。replace()類似,只是它不會將新狀態推送到歷史記錄中。

使用示例:

this.$router.push('about') //命名路由,稍後查看
this.$router.push({ path: 'about' })
this.$router.push({ path: 'post', query: { post_slug: 'hello-world' } }) //使用查詢參數(post?post_slug=hello-world)
this.$router.replace({ path: 'about' })

go()可以前進和後退,接受一個可能為正或負的數字來倒退或前進歷史記錄:

this.$router.go(-1) //後退1步
this.$router.go(1) //向前1步

定義路由

在這個例子中,我使用了一個Vue單文件組件

在模板中,我使用一個nav標籤,其中包含3個router-link組件,這些組件通過to屬性分配一個標籤(Home/Login/About)和一個URL。

router-view組件是Vue Router將匹配當前URL的內容放入其中的地方。

<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>

一個router-link組件默認渲染為一個a標籤(你可以更改它)。每次路由發生更改,無論是通過點擊鏈接還是更改URL時,都會向與活動路由相關聯的元素添加一個router-link-active類,使您能夠對其進行樣式設置。

在JavaScript部分,我們首先包含並安裝了路由器,然後定義了3個路由组件

我們將它們傳遞給router對象的初始化,然後將此對象傳遞給Vue根實例。

代碼如下:

<script>
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const Home = {
 template: '<div>Home</div>'
}

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>

通常,在Vue應用程式中,您使用以下方式實例化並安裝根應用程式:

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

當使用Vue Router時,您不需要傳遞render屬性,而是使用router

上面的示例中使用的語法:

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

是以下方式的縮寫:

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

在上面的示例中,我們將routes數組傳遞給了VueRouter構造函數。該數組中的每個路由都具有pathcomponent參數。

如果您還傳遞一個name參數,則是一個命名路由

使用命名路由來將參數傳遞給路由的push和replace方法

還記得我們以前如何使用路由器對象來推送新狀態的嗎?

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

使用命名路由,我們可以將參數傳遞給新路由:

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

對於replace()也是一樣的:

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

當用戶點擊了router-link時會發生什麼

應用程式會渲染與鏈接所傳遞的URL相匹配的路由組件。

處理URL的新路由組件將被實例化並調用其guards,舊的路由組件將被摧毀。

路由保護

既然我們提到了guards,讓我們來介紹一下。

你可以將它們看作生命週期鉤子或中間件,它們是在應用程式執行期間的特定時間點調用的函數。你可以介入並修改路由的執行,重定向或取消請求。

通過在路由器的beforeEach()afterEach()屬性中添加回調函數,你可以擁有全局的路由保護。

  • beforeEach()在導航確認之前調用
  • beforeResolve()在執行beforeEach並調用所有組件的beforeRouterEnterbeforeRouteUpdate保護之後,但在導航確認之前。如果您想要進行最終檢查
  • afterEach()在導航確認後調用

“導航確認”是什麼意思?我們稍後會看到。在此之前,將其視為“應用程式可以轉到該路由”。

使用方法如下:

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

tofrom代表我們要前往和從哪裡來的路由對象。beforeEach還有一個額外的參數next,如果我們以false調用它,將會阻止導航,並導致它未確認。就像在Node中間件中一樣,如果你熟悉的話,應該總是調用next(),否則執行將被阻塞。

單個路由組件也有guards:

  • beforeRouteEnter(from, to, next) 在當前路由確認之前調用
  • beforeRouteUpdate(from, to, next) 在路由更改但仍使用該組件(對於動態路由,請參見下文)的情況下調用
  • beforeRouteLeave(from, to, next) 在我們從當前路由移開時調用

我們之前提到過導航。要確定是否確認到某個路由,Vue Router執行了一些檢查:

  • 它在當前組件中調用beforeRouteLeave保護
  • 它調用路由器的beforeEach()保護
  • 它在任何需要重複使用的組件中,調用beforeRouteUpdate(),如果有的話
  • 它在路由對象上調用beforeEnter()保護(我沒有提到,但你可以在這裡找到它)
  • 它在應該進入的組件中調用beforeRouterEnter()保護
  • 它在路由器的beforeResolve()保護中調用
  • 如果一切順利,導航確認!
  • 它調用路由器的afterEach()保護

您可以使用特定於路由的保護(beforeRouteEnterbeforeRouteUpdate,在動態路由的情況下)作為生命週期鉤子使用,因此您可以開始進行數據提取請求,例如。

動態路由

上面的示例根據URL顯示不同的視圖,處理//login/about路徑。

非常常見的需求是處理動態路由,比如在/post/下有所有帖子,每個帖子都有一個別名:

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

您可以使用動態片段來實現這一點。

上面的示例是使用靜態片段的:

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

我們增加了一個動態片段來處理部落格帖子:

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

注意:post_slug語法。這表示您可以使用任何字符串,並將其映射到post_slug佔位符。

您不僅限於這種類型的語法。Vue依賴於此庫來解析動態路由,您可以使用Regular Expressions實現更多功能。

現在,在Post路由組件中,我們可以使用$route引用路由,並使用$route.params.post_slug引用帖子別名。

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

我們可以使用此參數從後端加載內容。

您可以有多個動態片段,它們在同一個URL中:

/post/:author/:post_slug

還記得我們在以前談到用戶瀏覽到新路由時會發生什麼嗎?

對於動態路由的情況,情況是有些不同的。

為了更高效,Vue並不銷毀當前的路由組件並重新實例化它,而是重用當前的實例。

當發生這種情況時,Vue會調用beforeRouteUpdate生命周期事件。在那裡,您可以執行任何需要的操作:

const Post = {
 template: '<div>Post: {{ $route.params.post_slug }}</div>'
 beforeRouteUpdate(to, from, next) {
 console.log(`Updating slug from ${from} to ${to}`)
 next() //確保始終調用next()
 }
}

使用props

在示例中,我使用$route.params.*來訪問路由數據。一個組件不應與路由器緊密耦合,相反,我們可以使用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 }
 ]
})

注意將props: true傳遞給路由對象以啟用此功能。

嵌套路由

我之前提到您可以在同一個URL中有尽可能多的動態片段,比如:

/post/:author/:post_slug

因此,假設我們有一個負責第一個動態片段的Author組件:

<template>
 <div id="app">
 <router-view></router-view>
 </div>
</template>

<script>
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

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>

我們可以在Author模板中插入第二個router-view組件實例:

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

我們增加Post組件:

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

然後我們將內部動態路由注入VueRouter配置中:

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