一、为什么需要导航守卫?
有时候我们需要通过路由来进行一些操作,比如最常见的登录权限验证,当用户满足条件时,才让其进入导航,否则就取消跳转,并跳到登录界面让其登录
我们有很多方法植入路由的导航过程:全局的,单个路由独享的,或者组件级的
二、全局守卫
vue-router全局有三个守卫:
1、router.beforeEach 全局前置守卫 ,进入路由前
2、router.beforeResolve 全局解析守卫(2.5.0+),在beforeRouteEnter调用之后调用
3、router.afterEach 全局后置钩子,进入路由之后
使用方法:
在main.js入口文件中:
import router from './router' //引入路由
router.beforeEach((to,from,next) => {
next();
});
router.beforeResolve((to,from,next) => {
next();
});
router.afterEach((to,from) => {
console.log("afterEach" 全局后置钩子)
})
to, from, next三个参数
to和from是将要进入和将要离开的路由对象,路由对象指的是平时通过this.$route获取到的路由对象
next:function 这个参数是个函数,且必须调用,否则不能进入路由
·next() 进入该路由
·next(false) 取消进入路由,url地址重置为from路由地址,也就是将要离开的路由地址
·next 跳转新路由,当前的导航被中断,重新开始一个新的导航
我们允许这样的跳转:next('path地址')
next({path:""})
next({name:""})
且允许设置诸如:
replace:true、name:"home"的选项
三、路由独享守卫
const router = new Router({
routes:[
{
path:'/foo',
component:Foo,
beforeEnter:(to,from,next) => {
参数的用法都一样,调用的顺序在全局前置守卫的后面,所以不会被全局守卫覆盖
}
}
]
})
四、路由组件内守卫
1、beforeRouteEnter 进入路由前
2、beforeRouteUpdate 路由复用同一组件时
3、beforeRouteLeave 离开当前路由时
beforeRouteEnter (to,from.next) {
//在路由独享守卫后调用,! 不 ! 能 获取组件实例this,组件实例还没有被创建
}
beforeRouteUpdate(to,from,next){
//在当前路由改变,但是该组件被复用时调用,可以访问组件实例this
//举例来说:对于一个带有动态参数的路径:/foo/:id,在/foo/1和/foo/2之间跳转的时候
//由于会渲染同样的Foo组件,因此组件实例会被复用。这个钩子就会在这种情况下被调用
}
beforeRouteLeave(to,from,next){
//导航离开该组件的对应路由时调用,可以访问组件实例
}
-------------------------------------------------------------
##beforeRouteEnter访问this
因为钩子在组件实例还没有被创建的时候调用,所以不能获取组件实例this,可以通过传一个回调给next来访问组件实例
但是回调的执行时机在mounted后面,所以对this的访问意义不大,可以放在created或者mounted里面
beforeRouteEnter(to,from,next){
//在路由独享守卫后调用
console.log('在路由独享守卫后调用')
next(vm =>{
//通过vm访问组件实例this,执行回调的时机在mounted后面
})
}
##beforeRouteLeave
导航离开该组件的对应路由时调用,我们用它来禁止用户离开,比如还未保存草稿,或者在用户离开前,将setInterval销毁,防止离开之后,定时器还在调用
beforeRouteLeave(to,from,next){
if(文章保存){
next();//允许离开或者可以跳到别的路由
}else{
next(false);//取消离开
}
}
五、关于钩子的一些知识
1、路由钩子函数的错误捕获
如果我们在全局守卫/路由独享守卫/组件路由守卫的钩子函数中有错误,可以这样捕获
router.onError(callback => {
console.log(callback,"callback")
})
2、跳转死循环,页面永远空白
router.beforeEach((to, from, next) => {
if(登录){
next();
}else{
next({name:"login"});
}
})
这样的逻辑看似是对的,但是当我们跳转到login之后,因为此时还是未登录状态,所以会一直跳转到login形成死循环
页面会一直空白,所以,我们要把判断条件稍微改变一下
if(登录 || to.name === 'login'){ next() }
//登录或者将要前往login页面的时候,就允许进路由
3、全局后置钩子的跳转
文档中提到因为router.afterEach()不接受next函数所以也不会改变导航本身:
意思就是只能当成一个钩子来使用,但是也可以用于路由跳转
//main.js入口文件
import router from './router' //引入路由
router.afterEach((to,from) => {
if(未登录 && to.name !== 'login'){
router.push({name:"login"}); //跳转login
}
})
六、完整的路由导航解析流程(不包括其他生命周期)
1、触发进入其他路由
2、调用要离开路由的组件守卫:beforeRouteLeave
3、调用全局前置守卫:beforeEach
4、在重用的组件里调用:beforeRouteUpdate
5、调用路由独享守卫:beforeEnter
6、解析异步路由组件
7、在将要进入的路由组件中调用:beforeRouteEnter
8、调用全局解析守卫:beforeResolve
9、导航被确认
10、调用全局后置钩子的afterEach钩子
11、触发DOM更新
12、执行beforeRouteEnter守卫中传给next的函数