1.導(dǎo)航守衛(wèi)是什么
官方這么說:
正如其名以故,
*vue-router*
提供的導(dǎo)航守衛(wèi)主要用來通過跳轉(zhuǎn)或取消的方式守衛(wèi)導(dǎo)航。
好吧,看不懂胸私,就好(當(dāng))好(廢)理(話)解(吧)下。其實煤傍,導(dǎo)航守衛(wèi)就是路由跳轉(zhuǎn)過程中的一些鉤子函數(shù)盖文,再直白點路由跳轉(zhuǎn)是一個大的過程嘱蛋,這個大的過程分為跳轉(zhuǎn)前中后等等細(xì)小的過程蚯姆,在每一個過程中都有一函數(shù),這個函數(shù)能讓你操作一些其他的事兒的時機(jī)洒敏,這就是導(dǎo)航守衛(wèi)龄恋。
2.導(dǎo)航守衛(wèi)全解析
先看一個鉤子函數(shù)執(zhí)行后輸出的順序截圖吧,一般講解都會在之后呈現(xiàn)凶伙,給大家換種思路(也就是先預(yù)習(xí)再學(xué)習(xí)最后復(fù)習(xí))
[圖片上傳失敗...(image-b044c6-1632499247491)]
好吧不知道的估計看不懂吧郭毕!不過我希望你能看到一個點能多倒回來看看這個順序,前方干貨預(yù)警
導(dǎo)航守衛(wèi)分為:全局的函荣、單個路由獨享的显押、組件內(nèi)的三種。分別來看一下:
【全局的】:是指路由實例上直接操作的鉤子函數(shù)傻挂,他的特點是所有路由配置的組件都會觸發(fā)乘碑,直白點就是觸發(fā)路由就會觸發(fā)這些鉤子函數(shù),如下的寫法金拒。鉤子函數(shù)按執(zhí)行順序包括beforeEach兽肤、beforeResolve(2.5+)、afterEach三個(以下的鉤子函數(shù)都是按執(zhí)行順序講解的):
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
[beforeEach]:在路由跳轉(zhuǎn)前觸發(fā),參數(shù)包括to,from,next(參數(shù)會單獨介紹)三個资铡,這個鉤子作用主要是用于登錄驗證电禀,也就是路由還沒跳轉(zhuǎn)提前告知,以免跳轉(zhuǎn)了再通知就為時已晚笤休。
[beforeResolve](2.5+):這個鉤子和beforeEach類似尖飞,也是路由跳轉(zhuǎn)前觸發(fā),參數(shù)也是to,from,next三個宛官,和beforeEach區(qū)別官方解釋為:
區(qū)別是在導(dǎo)航被確認(rèn)之前葫松,同時在所有組件內(nèi)守衛(wèi)和異步路由組件被解析之后,解析守衛(wèi)就被調(diào)用底洗。
即在 beforeEach 和 組件內(nèi)beforeRouteEnter 之后腋么,afterEach之前調(diào)用。
[afterEach]:和beforeEach相反亥揖,他是在路由跳轉(zhuǎn)完成后觸發(fā)珊擂,參數(shù)包括to,from沒有了next(參數(shù)會單獨介紹),他發(fā)生在beforeEach和beforeResolve之后,beforeRouteEnter(組件內(nèi)守衛(wèi)费变,后講)之前摧扇。
【路由獨享的】是指在單個路由配置的時候也可以設(shè)置的鉤子函數(shù),其位置就是下面示例中的位置挚歧,也就是像Foo這樣的組件都存在這樣的鉤子函數(shù)扛稽。目前他只有一個鉤子函數(shù)beforeEnter:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
[beforeEnter]:和beforeEach完全相同,如果都設(shè)置則在beforeEach之后緊隨執(zhí)行滑负,參數(shù)to在张、from、next
【組件內(nèi)的】:是指在組件內(nèi)執(zhí)行的鉤子函數(shù)矮慕,類似于組件內(nèi)的生命周期帮匾,相當(dāng)于為配置路由的組件添加的生命周期鉤子函數(shù)。鉤子函數(shù)按執(zhí)行順序包括beforeRouteEnter痴鳄、beforeRouteUpdate (2.2+)瘟斜、beforeRouteLeave三個,執(zhí)行位置如下:
<template>
...
</template>
export default{
data(){
//...
},
beforeRouteEnter (to, from, next) {
// 在渲染該組件的對應(yīng)路由被 confirm 前調(diào)用
// 不痪寻!能螺句!獲取組件實例 `this`
// 因為當(dāng)守衛(wèi)執(zhí)行前,組件實例還沒被創(chuàng)建
},
beforeRouteUpdate (to, from, next) {
// 在當(dāng)前路由改變橡类,但是該組件被復(fù)用時調(diào)用
// 舉例來說蛇尚,對于一個帶有動態(tài)參數(shù)的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉(zhuǎn)的時候猫态,
// 由于會渲染同樣的 Foo 組件佣蓉,因此組件實例會被復(fù)用披摄。而這個鉤子就會在這個情況下被調(diào)用。
// 可以訪問組件實例 `this`
},
beforeRouteLeave (to, from, next) {
// 導(dǎo)航離開該組件的對應(yīng)路由時調(diào)用
// 可以訪問組件實例 `this`
}
}
<style>
...
</style>
[beforeRouteEnter]:路由進(jìn)入之前調(diào)用勇凭,參數(shù)包括to疚膊,from,next虾标。該鉤子在全局守衛(wèi)beforeEach和獨享守衛(wèi)beforeEnter之后寓盗,全局beforeResolve和全局afterEach之前調(diào)用,要注意的是該守衛(wèi)內(nèi)訪問不到組件的實例璧函,也就是this為undefined傀蚌,也就是他在beforeCreate生命周期前觸發(fā)。在這個鉤子函數(shù)中蘸吓,可以通過傳一個回調(diào)給 next來訪問組件實例善炫。在導(dǎo)航被確認(rèn)的時候執(zhí)行回調(diào),并且把組件實例作為回調(diào)方法的參數(shù)库继,可以在這個守衛(wèi)中請求服務(wù)端獲取數(shù)據(jù)箩艺,當(dāng)成功獲取并能進(jìn)入路由時,調(diào)用next并在回調(diào)中通過 vm訪問組件實例進(jìn)行賦值等操作宪萄,(next中函數(shù)的調(diào)用在mounted之后:為了確保能對組件實例的完整訪問)艺谆。
beforeRouteEnter (to, from, next) {
// 這里還無法訪問到組件實例,this === undefined
next( vm => {
// 通過 `vm` 訪問組件實例
})
}
[beforeRouteUpdate] (v 2.2+):在當(dāng)前路由改變時拜英,并且該組件被復(fù)用時調(diào)用静汤,可以通過this訪問實例。參數(shù)包括to居凶,from虫给,next∨偶啵可能有的同學(xué)會疑問狰右,what is 路由改變 or what is 組件被復(fù)用杰捂?
- 對于一個帶有動態(tài)參數(shù)的路徑 /foo/:id舆床,在 /foo/1 和 /foo/2 之間跳轉(zhuǎn)的時候,組件實例會被復(fù)用嫁佳,該守衛(wèi)會被調(diào)用
- 當(dāng)前路由query變更時挨队,該守衛(wèi)會被調(diào)用
[beforeRouteLeave]:導(dǎo)航離開該組件的對應(yīng)路由時調(diào)用,可以訪問組件實例this
蒿往,參數(shù)包括to盛垦,from,next瓤漏。
至此腾夯,所有鉤子函數(shù)介紹完畢颊埃。
屢一下哈:
全局路由鉤子:beforeEach(to,from, next)、beforeResolve(to,from, next)蝶俱、afterEach(to,from)班利;
獨享路由鉤子:beforeEnter(to,from, next);
組件內(nèi)路由鉤子:beforeRouteEnter(to,from, next)榨呆、beforeRouteUpdate(to,from, next)罗标、beforeRouteLeave(to,from, next)
不知道你是否還記得to、from积蜻、next這三個參數(shù)
下面請重頭把這幾個鉤子函數(shù)的參數(shù)看一遍闯割,細(xì)心的同學(xué)可以看見在afterEach鉤子中參數(shù)沒有next,為什么呢竿拆?
3.導(dǎo)航守衛(wèi)回調(diào)參數(shù)
to:目標(biāo)路由對象宙拉;
from:即將要離開的路由對象;
next:他是最重要的一個參數(shù)丙笋,他相當(dāng)于佛珠的線鼓黔,把一個一個珠子逐個串起來。以下注意點務(wù)必牢記:
1.但凡涉及到有next參數(shù)的鉤子不见,必須調(diào)用next() 才能繼續(xù)往下執(zhí)行下一個鉤子澳化,否則路由跳轉(zhuǎn)等會停止。
2.如果要中斷當(dāng)前的導(dǎo)航要調(diào)用next(false)稳吮。如果瀏覽器的 URL 改變了 (可能是用戶手動或者瀏覽器后退按鈕)缎谷,那么 URL 地址會重置到from
路由對應(yīng)的地址。(主要用于登錄驗證不通過的處理)
3.當(dāng)然next可以這樣使用灶似,next('/') 或者 next({ path: '/' }): 跳轉(zhuǎn)到一個不同的地址列林。意思是當(dāng)前的導(dǎo)航被中斷,然后進(jìn)行一個新的導(dǎo)航酪惭∠3眨可傳遞的參數(shù)與router.push中選項一致。
4.在beforeRouteEnter鉤子中next((vm)=>{})內(nèi)接收的回調(diào)函數(shù)參數(shù)為當(dāng)前組件的實例vm春感,這個回調(diào)函數(shù)在生命周期mounted之后調(diào)用砌创,也就是,他是所有導(dǎo)航守衛(wèi)和生命周期函數(shù)最后執(zhí)行的那個鉤子鲫懒。
5.next(error): (v2.4.0+) 如果傳入 next
的參數(shù)是一個 Error
實例嫩实,則導(dǎo)航會被終止且該錯誤會被傳遞給 [router.onError()](https://link.zhihu.com/?target=https%3A//router.vuejs.org/zh-cn/api/router-instance.html%23%25E6%2596%25B9%25E6%25B3%2595)
注冊過的回調(diào)。
4.總結(jié)
好了窥岩,還記得那個截圖嗎甲献,我們再看一遍
[圖片上傳失敗...(image-940ea2-1632499247491)]
我們最后屢一下順序:
當(dāng)點擊切換路由時:beforeRouterLeave-->beforeEach-->beforeEnter-->beforeRouteEnter-->beforeResolve-->afterEach-->beforeCreate-->created-->beforeMount-->mounted-->beforeRouteEnter的next的回調(diào)
當(dāng)路由更新時:beforeRouteUpdate