"導航" 表示路由正在發生改變
vue-router
提供的導航守衛主要用來通過跳轉或取消的方式守衛導航。有多種機會植入路由導航過程中,他們分為三種:
- 全域性的
- router.beforeEach
- router.beforeResolve
- router.afterEach
- 單個路由獨享的
- beforeEnter
- 元件級的
- beforeRouteEnter
- beforeRouteUpdate
- beforeRouteLeave
注:引數或查詢的改變並不會觸發進入/離開的導航守衛 (你可以通過觀察 $route
物件來應對這些變化,或使用 beforeRouteUpdate
的元件內守衛。)
給一張圖直觀的看一下:
全域性前置守衛
可以使用 router.beforeEach
註冊一個全域性前置守衛
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
複製程式碼
當一個導航觸發時,全域性前置守衛會按照建立順序呼叫。守衛是非同步解析執行,此時導航在所有守衛 resolve 完之前一直處於等待中
引數
每個守衛方法接收三個引數:
to:Route
:即將要進入的目標 路由物件from:Route
:當前導航正要離開的路由next:Function
:一定要呼叫該方法來resolve
這個鉤子。執行效果依賴next
方法的呼叫引數next()
進行管道中的下一個鉤子。如果全部鉤子執行完了,則導航的狀態就是 confirmed (確認的)。next(false)
: 中斷當前的導航。如果瀏覽器的 URL 改變了 (可能是使用者手動或者瀏覽器後退按鈕),那麼 URL 地址會重置到from
路由對應的地址。next('/')
或者next({ path: '/' })
: 跳轉到一個不同的地址。當前的導航被中斷,然後進行一個新的導航。你可以向next
傳遞任意位置物件,且允許設定諸如replace: true
、name: 'home'
之類的選項以及任何用在router-link
的to prop
或router.push
中的選項。next(error)
: (2.4.0+) 如果傳入next
的引數是一個 Error 例項,則導航會被終止且該錯誤會被傳遞給router.onError()
註冊過的回撥。
確保要呼叫next
方法,否則鉤子就不會被resolved
全域性解析守衛
可以用router.beforeResolve
註冊一個全域性守衛。這和 router.beforeEach
類似,區別是在導航被確認之前,同時在所有元件內守衛和非同步路由元件被解析之後,解析守衛就被呼叫。
全域性後置鉤子
可以註冊一個全域性後置鉤子,然而和守衛不同的是,這些鉤子不會接受next
函式也不會改變導航本身
router.afterEach((to, from) => {
// ...
})
複製程式碼
路由獨享的守衛
可以在路由配置上直接定義 beforeEnter
守衛:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
複製程式碼
這些守衛與全域性前置守衛的方法引數是一樣的。
元件內的守衛
當然,也可以在路由元件內直接定義以下路由導航守衛:
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染該元件的對應路由被 confirm 前呼叫
// 也就是進入新的元件時
// 不能獲取元件例項 `this`
// 因為當守衛執行前,元件例項還沒被建立
},
beforeRouteUpdate (to, from, next) {
// 在當前路由改變,但是該元件被複用時呼叫
// 舉例來說,對於一個帶有動態引數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候,
// 由於會渲染同樣的 Foo 元件,因此元件例項會被複用。而這個鉤子就會在這個情況下被呼叫。
// 可以訪問元件例項 `this`
},
beforeRouteLeave (to, from, next) {
// 導航離開該元件的對應路由時呼叫
// 可以訪問元件例項 `this`
}
}
複製程式碼
beforeRouteEnter
守衛 不能 訪問 this
,因為守衛在導航確認前被呼叫,因此即將登場的新元件還沒被建立。
不過,你可以通過傳一個回撥給 next
來訪問元件例項。在導航被確認的時候執行回撥,並且把元件例項作為回撥方法的引數。
beforeRouteEnter (to, from, next) {
next(vm => {
// 通過 `vm` 訪問元件例項
})
}
複製程式碼
注意 beforeRouteEnter
是支援給 next
傳遞迴調的唯一守衛。對於 beforeRouteUpdate
和 beforeRouteLeave
來說,this
已經可用了,所以不支援傳遞迴調,因為沒有必要了。
beforeRouteUpdate (to, from, next) {
// just use `this`
this.name = to.params.name
next()
}
複製程式碼
beforeRouteUpdate
是在路徑發生改變時呼叫
這個離開守衛通常用來禁止使用者在還未儲存修改前突然離開。該導航可以通過 next(false)
來取消。
beforeRouteLeave (to, from , next) {
const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
if (answer) {
next()
} else {
next(false)
}
}
複製程式碼
完整的導航解析流程
1.導航被觸發
2.在失活的元件裡呼叫離開守衛。
3.呼叫全域性的 beforeEach
守衛。
4.在重用的元件裡呼叫 beforeRouteUpdate
守衛 (2.2+)。
5.在路由配置裡呼叫 beforeEnter
。
6.解析非同步路由元件。
7.在被啟用的元件裡呼叫 beforeRouteEnter
。
8.呼叫全域性的 beforeResolve
守衛 (2.5+)。
9.導航被確認。
10.呼叫全域性的 afterEach
鉤子。
11.觸發 DOM
更新。
12.用建立好的例項呼叫 beforeRouteEnter
守衛中傳給 next
的回撥函式。
程式碼示例
//Router定義
Vue.use(Router)
const router = new Router({
...
})
//導航守衛
router.beforeEach((to, from, next) => {
console.log("導航前置守衛: beforeEach,");
next();
})
router.afterEach((to, from) => {
console.log("導航後置守衛: afterEach,");
})
router.beforeResolve ((to, from, next) => {
console.log("導航解析守衛: beforeResolve,");
next();
})
複製程式碼
元件鉤子:
export default {
//鉤子
beforeCreate(){
console.log("元件鉤子: beforeCreate");
},
created(){
console.log("元件鉤子: created");
},
beforeMount(){
console.log("元件鉤子: beforeMount");
},
mounted(){
console.log("元件鉤子: mounted");
},
beforeUpdate(){
console.log("元件鉤子: beforeUpdate");
},
updated(){
console.log("元件鉤子: updated");
},
beforeDestroy(){
console.log("元件鉤子: beforeDestroy");
},
destoryed(){
console.log("元件鉤子: destoryed");
},
beforeRouteEnter (to, from, next) {
console.log("元件內部守衛: beforeRouteEnter,");
next()
},
beforeRouteUpdate (to, from, next) {
console.log("元件內部守衛: beforeRouteUpdate,");
next()
},
beforeRouteLeave (to, from, next) {
console.log("元件內部守衛: beforeRouteLeave,");
next()
}
}
複製程式碼
執行輸出順序:
導航前置守衛: beforeEach
元件內部守衛: beforeRouteEnter
導航解析守衛: beforeResolve
導航後置守衛: afterEach
元件鉤子: beforeCreate
元件鉤子: created
元件鉤子: beforeMount
元件鉤子: mounted
//執行跳轉
元件內部守衛: beforeRouteLeave
導航前置守衛: beforeEach
導航解析守衛: beforeResolve
導航後置守衛: afterEach
元件鉤子: beforeDestroy
複製程式碼
關於 Vue元件 的生命週期與鉤子函式,請參考我的文章《Vue 生命週期與鉤子函式》