1. 前言
1.路由確實(shí)在
vue
大型項(xiàng)目中聽(tīng)常用的,挺重要的,但是一般的小項(xiàng)目其實(shí)不用也沒(méi)事
2.大家覺(jué)得難的 可能重點(diǎn)是路由守衛(wèi)
3.那就試試自己能不能講明白吧
4.當(dāng)然還是建議大家看看 官網(wǎng)的路由守衛(wèi)
2. 先從路由監(jiān)聽(tīng)說(shuō)起吧
2.1 首先路由系列的文章vue路由-2編程式導(dǎo)航存在通過(guò)路由切換的時(shí)候,
created
直走一次的問(wèn)題,
2.2 解決方案 監(jiān)聽(tīng) -1
參數(shù)的名字 一般都叫
to
from
或者newV, oldV
to: Route
: 即將要進(jìn)入的目標(biāo) 路由對(duì)象
from: Route
: 當(dāng)前導(dǎo)航正要離開(kāi)的路由
watch:{
$route(to,from){
console.log(from.path);//從哪來(lái)
console.log(to.path);//到哪去
//界面變化了就發(fā)請(qǐng)求
}
},
這種寫法也有個(gè)問(wèn)題,第一次的時(shí)候不走
2.3 解決方案 監(jiān)聽(tīng)-2
immediate:true
設(shè)置 立刻監(jiān)聽(tīng),第一次切換也會(huì)走的
watch:{
$route:{
immediate:true,
handler(newValue,oldValue){
console.log("詳情頁(yè)---newV:",newValue);
console.log("詳情頁(yè)---oldV:",oldValue);
}
},
},
3.導(dǎo)航守衛(wèi)
3.1 官方定義
正如其名,vue-router 提供的導(dǎo)航守衛(wèi)主要用來(lái)通過(guò)跳轉(zhuǎn)或取消的方式守衛(wèi)導(dǎo)航。有多種機(jī)會(huì)植入路由導(dǎo)航過(guò)程中:全局的, 單個(gè)路由獨(dú)享的, 或者組件級(jí)的。
3.2 場(chǎng)景
路由守衛(wèi)嘛 就是保護(hù)路由的 ,怎么保護(hù)呢
主要就是在進(jìn)入路由之前進(jìn)行攔截
一般都是 某些界面必須登錄才能訪問(wèn)的時(shí)候做個(gè)守衛(wèi),比如
最近某些購(gòu)物類網(wǎng)站,點(diǎn)擊購(gòu)物車相關(guān)操作話,如果你沒(méi)有登錄的話,會(huì)直接跳轉(zhuǎn)到登錄界面;
在以前是會(huì)正常跳到購(gòu)物車界面,付賬的時(shí)候在登錄,登錄后購(gòu)物車信息是都在的
5. 全局守衛(wèi)配置
5.1 標(biāo)記需要進(jìn)行守衛(wèi)的路由
一般通過(guò)路由配置
meta
屬性
路由文件
{
path: '/address',
name: 'Address',
component: () => import('../views/address.vue'),
meta:{
title: "標(biāo)題",
icon: "圖標(biāo)",
needLogin:true
}
},
1.
meta
哈哈沒(méi)想到這個(gè)時(shí)候正式元宇宙大火的概念
2.扯回整體, 這里的meta
是一些原配置信息
3.needLogin
用來(lái)標(biāo)記某個(gè)頁(yè)面路由是否需要登錄才能訪問(wèn)
4.title
實(shí)際開(kāi)發(fā)中,如果配置菜單 也可以配置標(biāo)題
5.icon
實(shí)際開(kāi)發(fā)中,如果配置菜單 也可以配置菜單圖標(biāo)
5.2守衛(wèi)邏輯
- 判斷哪個(gè)路由需要守衛(wèi)
if(to.meta.needLogin)
- 不需要守衛(wèi)的 直接 走
else next()
- 需要守衛(wèi)的進(jìn)行第二步判斷, 當(dāng)前是否登錄
登錄的時(shí)候發(fā)請(qǐng)求 請(qǐng)求成功 存放 一個(gè)auth
或者token
到本地localStorage
- 如果現(xiàn)在已經(jīng)登錄 直接
next()
放行
5.如果沒(méi)登錄 嘿嘿此路是我開(kāi),此樹(shù)是我栽,要想過(guò),得聽(tīng)話,
回去登錄去
注意的是 這里跳轉(zhuǎn)到登錄界面,需要把攔截路由的地址傳過(guò)去,
為啥傳???
那還不是為了用戶體驗(yàn),為了顧客,為了邏輯閉環(huán)
比如用戶從點(diǎn)擊購(gòu)物車界面 跳轉(zhuǎn)到了登錄界面,用戶登錄后,肯定要給界面重置到 購(gòu)物車界面嘛,
5.3 具體守衛(wèi)代碼 方式-1
// 全局守衛(wèi)
router.beforeEach((to,from,next)=>{
// 判斷路由是否需要守衛(wèi)
//meta數(shù)據(jù)的方式
if(to.meta.needLogin){
// 是否登錄
if(localStorage.token){
next()
}else{
next("/login?redirect="+to.fullPath)
}
}else{
//不需要守衛(wèi),直接放行
next()
}
})
export default router
5.4具體守衛(wèi)代碼 方式-2
router.beforeEach((to, from) => {
if (to.meta.needLogin) {//說(shuō)明當(dāng)前路由需要登錄之后才可進(jìn)入
if (!localStorage.token) {//還沒(méi)登錄 不為空 就行 簡(jiǎn)單的判斷
// return "/login?redirect=" + to.name;
return "/login?redirect=" + to.fullPath;
}
}
})
這個(gè)不用
next
,但如果參數(shù)寫了next
就必須用,不然不放行嘛,界面就一個(gè)也出不來(lái)
to.name
的方式 傳的是 命名路由 跳轉(zhuǎn)的時(shí)候也需要使用命名路由跳轉(zhuǎn)
this.$router.push({ name: this.$route.query.redirect});
to.fullPath
的方式 傳的是path
路徑
用push
也行,但是也可用replace
this.$router.replace(this.$route.query.to);
6. 登錄后跳回去的配置
loginBtn() {
this.isdisabled = true;
setTimeout(() => {
alert("登錄成功");
this.isdisabled = false;
localStorage.token = "yzs假冒token";
// 登錄成功之后 回到被攔截的頁(yè)面
this.$router.replace(this.$route.query.redirect);
}
}, 3000);
},
守衛(wèi)的時(shí)候傳參方式
1.可以傳 通過(guò)
query
傳遞 path路徑
2.也可以通過(guò)params
傳參
3.注意登錄成功后 獲取值的方式就行
query:{redirect:"/two"} ,
params: { toRouterName: to.name }})
命名路由的寫法
this.$router.push({ name: this.$route.params.toRouterName });
這樣就形成了邏輯閉環(huán) ,當(dāng)然你還需退出或者注銷的時(shí)候修改狀態(tài)
7.單個(gè)路由守衛(wèi)
全局守衛(wèi),肯定是每個(gè)路由跳轉(zhuǎn)都要進(jìn)行判斷的,也就是
each
遍歷,這里面的效率問(wèn)題就需要考慮
所以,如果只是極個(gè)別的路由需要判斷,那就單獨(dú)守衛(wèi)
比如保護(hù)整村的人,和保護(hù)一個(gè)人那是完全不一樣的
注意和全局的不同
- 鉤子不一樣了,這個(gè)是
Enter
進(jìn)到這個(gè)路由了,判斷
2.因?yàn)橐呀?jīng)進(jìn)到這個(gè)路由了,自然也不需要在判斷哪個(gè)路由需要守衛(wèi)了- 直接判斷登錄狀態(tài)就行
{
path: '/cart',
name: 'Cart',
component: () => import("@/views/cart.vue"),
meta: {
title: "標(biāo)題",
icon: "圖標(biāo)",
needLogin: true
},
//************* */ 單個(gè)的路由守衛(wèi)
beforeEnter(to, from, next) {
// 判斷當(dāng)前是否登錄
if (localStorage.token) {
next()
} else {
next({ name: "Three",
query:{to:"/cart"} ,
params: { toRouterName: to.name },})
}
}
},
8. 組件級(jí)守衛(wèi)
1.和
methds
是同級(jí)的
2.beforeRouteEnter
和 單獨(dú)的守衛(wèi)beforeEnter
寫法是不一樣的
3.這個(gè)是存儲(chǔ)localStorage
的邏輯
4.login
頁(yè)和單個(gè)守衛(wèi)用的是一樣的
beforeRouteEnter(to, from, next) {
// 當(dāng)前是否登錄
if (localStorage.token) {
next();
} else {
next({ name: "Login", params: { toRouterName: to.name } });
}
},
9. 組件級(jí)守衛(wèi) 鉤子詳解
const Foo = {
template: `...`,
beforeRouteEnter(to, from, next) {
// 在渲染該組件的對(duì)應(yīng)路由被 confirm 前調(diào)用
// 不!能妻献!獲取組件實(shí)例 `this`
// 因?yàn)楫?dāng)守衛(wèi)執(zhí)行前,組件實(shí)例還沒(méi)被創(chuàng)建
},
beforeRouteUpdate(to, from, next) {
// 在當(dāng)前路由改變,但是該組件被復(fù)用時(shí)調(diào)用
// 舉例來(lái)說(shuō),對(duì)于一個(gè)帶有動(dòng)態(tài)參數(shù)的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉(zhuǎn)的時(shí)候礁扮,
// 由于會(huì)渲染同樣的 Foo 組件知举,因此組件實(shí)例會(huì)被復(fù)用。而這個(gè)鉤子就會(huì)在這個(gè)情況下被調(diào)用太伊。
// 可以訪問(wèn)組件實(shí)例 `this`
},
beforeRouteLeave(to, from, next) {
// 導(dǎo)航離開(kāi)該組件的對(duì)應(yīng)路由時(shí)調(diào)用
// 可以訪問(wèn)組件實(shí)例 `this`
}
}
1. 注意 Enter
鉤子不能訪問(wèn) this
因?yàn)槭匦l(wèi)在導(dǎo)航確認(rèn)前被調(diào)用雇锡,因此即將登場(chǎng)的新組件還沒(méi)被創(chuàng)建。
不過(guò)僚焦,你可以通過(guò)傳一個(gè)回調(diào)給 next來(lái)訪問(wèn)組件實(shí)例锰提。在導(dǎo)航被確認(rèn)的時(shí)候執(zhí)行回調(diào),并且把組件實(shí)例作為回調(diào)方法的參數(shù)。
beforeRouteEnter (to, from, next) {
next(vm => {
// 通過(guò) `vm` 訪問(wèn)組件實(shí)例
})
}
注意
beforeRouteEnter
是支持給next
傳遞回調(diào)的唯一守衛(wèi)立肘。對(duì)于beforeRouteUpdate
和beforeRouteLeave
來(lái)說(shuō)边坤,this
已經(jīng)可用了,所以不支持傳遞回調(diào)谅年,因?yàn)闆](méi)有必要了茧痒。
10.完整的導(dǎo)航解析流程
1.導(dǎo)航被觸發(fā)。
2.在失活的組件里調(diào)用beforeRouteLeave
守衛(wèi)融蹂。
3.調(diào)用全局的beforeEach
守衛(wèi)旺订。
4.在重用的組件里調(diào)用beforeRouteUpdate
守衛(wèi) (2.2+)。
5.在路由配置里調(diào)用beforeEnter
超燃。
6.解析異步路由組件区拳。
7.在被激活的組件里調(diào)用beforeRouteEnter
。
8.調(diào)用全局的beforeResolve
守衛(wèi) (2.5+)意乓。
9.導(dǎo)航被確認(rèn)樱调。
10.調(diào)用全局的afterEach
鉤子。
11.觸發(fā)DOM
更新洽瞬。
12.調(diào)用beforeRouteEnter
守衛(wèi)中傳給next
的回調(diào)函數(shù)本涕,創(chuàng)建好的組件實(shí)例會(huì)作為回調(diào)函數(shù)的參數(shù)傳入。
11. 想學(xué)習(xí)更多的實(shí)戰(zhàn)配置 可以去看下各大開(kāi)源的項(xiàng)目源碼
比如各大框架的
admin
模板