如何使用Vue Router,這是Vue應用程式中必不可少的一部分之一
簡介
在JavaScript網頁應用程式中,路由器是將目前顯示的視圖與瀏覽器地址欄內容同步的部分。
換句話說,它是當你在頁面上點擊某個元素時,使URL改變並顯示正確視圖的部分。
傳統上,網頁是基於URL構建的。當你訪問特定的URL時,會顯示特定的頁面。
隨著在瀏覽器內運行並改變使用者所見的應用程式的引入,許多應用程式打破了這種交互方式,你必須手動使用瀏覽器的History API更新URL。
當你需要將URL與應用程式中的視圖同步時,你就需要一個路由器。這是一個非常常見的需求,現代的主要框架現在都允許你進行路由管理。
Vue Router庫是Vue.js應用程式開發時的首選。Vue並不強制使用這個庫。你可以使用任何通用的路由庫,或者自己創建和History API集成,但是使用Vue Router的好處是它是官方的。
這意味著它是由維護Vue的同一群人維護的,所以你可以在框架中得到更一致的整合,並且保證它將始終與未來的版本兼容,無論是什麼版本。
安裝
Vue Router可以通過npm的vue-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的pushState
,replaceState
和go
方法。
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
構造函數。該數組中的每個路由都具有path
和component
參數。
如果您還傳遞一個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並調用所有組件的beforeRouterEnter
和beforeRouteUpdate
保護之後,但在導航確認之前。如果您想要進行最終檢查afterEach()
在導航確認後調用
“導航確認”是什麼意思?我們稍後會看到。在此之前,將其視為“應用程式可以轉到該路由”。
使用方法如下:
this.$router.beforeEach((to, from, next) => {
// ...
})
this.$router.afterEach((to, from) => {
// ...
})
to
和from
代表我們要前往和從哪裡來的路由對象。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()
保護
您可以使用特定於路由的保護(beforeRouteEnter
和beforeRouteUpdate
,在動態路由的情況下)作為生命週期鉤子使用,因此您可以開始進行數據提取請求,例如。
動態路由
上面的示例根據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
]
}]
})