十一、路由守卫
本文记录 5 个守卫:
- 全局守卫 2 个
- beforeEach:全局前置路由守卫
- afterEach:全局后置路由守卫
- 私有守卫 1 个
- beforeEnter:路由私有守卫
- 组件内守卫 2 个
- beforeRouteEnter:进入当前组件时调用
- beforeRouteLeave:离开当前组件时被调用
1、需求
Others 和 Home 人人都可访问, News 和 Message 必须是登录的用户才能访问
2、功能一览
3、思考一波
需求就是加权限,权限怎么加合适呢?
在路由跳转的时候加最合适,那应该怎么加呢?
挂上拦截器在路由跳转的时候拦截检查,那这个所谓的拦截器是什么呢?
全局前置-路由守卫 beforeEach!
4、全局前置-路由守卫 beforeEach
1、router/index.js
// 该文件专门用于创建整个应用的路由器
import VueRouter from 'vue-router'
//引入组件
import Others from '../views/Others'
import Home from '../views/Home'
import News from '../views/News'
import Message from '../views/Message'
import Details from '../views/Details'
//创建一个路由器
const router = new VueRouter({
routes:[ // 路由器管理的是什么呀?肯定是路由啊,全在这了!
{ // 一级路由
name: 'other',
path: '/others',
component: Others
},
{ // 一级路由
path: '/home',
component: Home,
children:[ // 为什么是数组?你凭什么断定他就只能生一个娃?
{ // 二级路由
name: 'news',
path: 'news', // 数组里的就不用加'/'了,路由器遍历的时候自动加上了
component: News,
},
{ // 二级路由
name: 'message',
path: 'message',
component: Message,
children: [
{ // 三级路由
name: 'detail',
path: 'details/:id/:title/:desc', // 配置占位符
component: Details,
props(route){ // router每次调的时候会把 $route 传进来,你想怎么取就怎么取!
return {
id: route.params.id,
title: route.params.title,
desc: route.params.desc
}
}
},
]
}
]
}
]
})
// 全局前置路由守卫(初始化和每次路由跳转之前调用)
router.beforeEach((to, from, next)=>{
console.log('to===>', to)
console.log('from===>', from)
console.log('next===>', next)
next()
})
// 暴露路由器
export default router
2、Result
5、优化 beforeEach
1、router/index.js
// 创建一个白名单
const whiteList = ['/others', '/home']
// 全局前置路由守卫(初始化和每次路由跳转之前调用)
router.beforeEach((to, from, next)=>{
// 白名单直接放行
if(whiteList.includes(to.path)){
next()
} else if(sessionStorage.getItem('id')){ // 是否登录,登录了会把id存到sessionStorage
next()
} else {
alert('暂无权限!')
}
})
2、Result
6、另一种思路:路由元数据 meta
我可不可以在配置路由的时候给每个路由挂个boolean类型参数peiqi,我在守卫里只要判断每个to的peiqi的真假就决定是否放行?请参观to的属性:
7、践行新思路
router/index.js
// ...
//创建一个路由器
const router = new VueRouter({
routes:[ // 路由器管理的是什么呀?肯定是路由啊,全在这了!
{ // 一级路由
name: 'other',
path: '/others',
component: Others,
meta: {
peiqi: true
}
},
{ // 一级路由
path: '/home',
component: Home,
meta: {
peiqi: true
}
children:[
// ... 其余的不配meta
]
}
]
})
// 全局前置路由守卫(初始化和每次路由跳转之前调用)
router.beforeEach((to, from, next)=>{
// 有peiqi且为true的放行!
if(to.meta.peiqi){
next()
} else if(sessionStorage.getItem('id')){ // 是否登录,登录了会把id存到sessionStorage
next()
} else {
alert('暂无权限!')
}
})
// 暴露路由器
export default router
8、全局后置-路由守卫 afterEach
有前置守卫,必然就有后置守卫!
这里提出新需求:每次跳转后页签标题要和当前组件契合
1、router/index.js
// ...
//创建一个路由器
const router = new VueRouter({
routes:[
{
name: 'other',
path: '/others',
component: Others,
meta: {
peiqi: true,
title: '其他'
}
},
{
path: '/home',
component: Home,
meta: {
peiqi: true,
title: '主页'
}
children:[
// ... 其余的meta也配title,但是篇幅过长自行体会
]
}
]
})
// ... 略
// 全局后置路由守卫(初始化和每次路由跳转之后调用)
// 后置没有next参数,走到这说明前置守卫已经放行,这里不再多此一举
router.afterEach((to, from)=>{
document.title = to.meta.title || 'Mr.Wang!'
})
// 暴露路由器
export default router
2、Result
9、独享路由守卫 beforeEnter
有全局的就有独享的,没错就是 beforeEnter!(注意!独享守卫只有前置,没有后置!)
执行顺序:beforeEach–>beforeEnter–>afterEach
这里提出新需求:跳转到 Others 的时候 title 改为 佩奇!
这里有大聪明就想问了,我直接把 Others 路由的 meta.title 改成 " 佩奇 " 不就得了吗?
咋滴,你就不想学 beforeEnter 了呗?
1、router/index.js
// ...
//创建一个路由器
const router = new VueRouter({
routes:[
{
name: 'other',
path: '/others',
component: Others,
meta: {
peiqi: true,
title: '其他'
},
// 独享路由守卫
beforeEnter(to, from, next){
to.meta.title = '佩奇!'
next()
}
},
// ... 略
]
})
// ... 略
// 暴露路由器
export default router
2、Result
10、组件内路由守卫 beforeRouteEnter/beforeRouteLeave
- beforeRouteEnter:通过路由规则进入该组件时调用
- beforeRouteLeave:通过路由规则离开该组件时调用
需求:我想在进入 Others 时开启一个定时,离开时关闭定时
1、测试
<template>
<h2>我是Others的内容</h2>
</template>
<script>
export default {
name:'Others',
// 通过路由规则进入该组件时调用
beforeRouteEnter (to, from, next) {
console.log("=======>beforeRouteEnter\n", this)
next()
},
// 通过路由规则离开该组件时调用
beforeRouteLeave (to, from, next) {
console.log("beforeRouteLeave=======>\n", this)
next()
}
}
</script>
2、Result
3、分析一波
beforeRouteEnter 里 this 未定义,那该如何操作当 vc 呢?
没错就是在 next 回调,参数就是当前 vc 实例!
4、CODE
<template>
<h2>我是Others的内容</h2>
</template>
<script>
export default {
name:'Others',
data(){
return {
others: 555,
timer: null
}
},
// 通过路由规则进入该组件时调用
beforeRouteEnter (to, from, next) {
console.log("=======>beforeRouteEnter\n", this)
next((instance)=>{
// 参数 instance 就是当前 Others 组件实例,可以获取当前 vc 身上的一切!
console.log('instance.others==>', instance.others)
instance.timer = setInterval(()=>{
console.log('Others 定时~')
}, 100)
})
},
// 通过路由规则离开该组件时调用
beforeRouteLeave (to, from, next) {
console.log("beforeRouteLeave=======>\n", this)
clearInterval(this.timer)
next()
}
}
</script>
5、Result
11、路由守卫总结
-
作用:对路由进行权限控制
-
分类:全局守卫、独享守卫、组件内守卫
-
全局守卫:
//全局前置守卫:初始化时执行、每次路由切换前执行 router.beforeEach((to,from,next)=>{ console.log('beforeEach',to,from) if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制 if(sessionStorage.getItem('id')){ //权限控制的具体规则 next() //放行 }else{ alert('暂无权限查看') // next({name:'guanyu'}) } }else{ next() //放行 } }) //全局后置守卫:初始化时执行、每次路由切换后执行 router.afterEach((to,from)=>{ console.log('afterEach',to,from) if(to.meta.title){ document.title = to.meta.title //修改网页的title }else{ document.title = 'vue_test' } })
-
独享守卫:
beforeEnter(to,from,next){ console.log('beforeEnter',to,from) if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制 if(localStorage.getItem('id')){ next() }else{ alert('暂无权限查看') } }else{ next() } }
-
组件内守卫:
//进入守卫:通过路由规则,进入该组件时被调用 beforeRouteEnter (to, from, next) { }, //离开守卫:通过路由规则,离开该组件时被调用 beforeRouteLeave (to, from, next) { }