vue-router中有3中导航守卫:
“导航”表示路由正在发生改变。
1、全局守卫:
(1)、全局前置守卫:
router.beforeEach((to, from, next) => {
if (to.name === 'Login') {
if (localStorage.getItem('token')) {
next({
name: 'Index'
})
} else {
next()
}
} else
if (!localStorage.getItem('token')) {
next({
name: 'Login'
})
} else {
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.afterEach(to => {
setTitle(to, router.app)
window.scrollTo(0, 0)
})
(2)、全局后置钩子:
router.afterEach((to,from) => {
//do someing
window.scrollTo(0, 0)
})
不同于前置守卫,后置钩子并没有 next 函数,也不会改变导航本身
2、路由独享守卫:在路由配置上直接定义 beforeEnter
守卫,这些守卫与全局前置守卫的方法参数是一样的。
{
path: '/index',
name: 'Index',
component: Index,
beforeEnter: (to, from, next) => {
console.log('如果有全局守卫,先全局后独享的')
}
},
3、组件内的守卫
data() {
return {
msg: 'Welcome to Your Vue.js App'
}
},
beforeRouteEnter(to, from, next) {
console.log('如果有全局路由,先全局后组件路由')
next(vm => {
console.log(vm.msg)
// 通过 `vm` 访问组件实例
})
},
beforeRouteUpdate(to, from, next) {
console.log('组件路由更新....')
// do someting
// 在当前路由改变,但是依然渲染该组件是调用
},
beforeRouteLeave:(to,from,next)=>{
if(confirm("确定离开此页面吗?") == true){
next()
}else{
next(false);
}
},
注: beforeRouteEnter 不能获取组件实例 this,因为当守卫执行前,组件实例被没有被创建出来,剩下两个钩子则可以正常获取组件实例 this;但是并不意味着在 beforeRouteEnter 中无法访问组件实例,我们可以通过给 next 传入一个回调来访问组件实例。在导航被确认是,会执行这个回调,这时就可以访问组件实例了,如:
beforeRouteEnter(to, from, next) {
console.log('组件路由')
next(vm => {
console.log(vm.msg)
// 通过 `vm` 访问组件实例
})
},
注:仅仅是 beforRouteEnter 支持给 next 传递回调,其他两个并不支持。因为归根结底,支持回调是为了解决 this 问题,而其他两个钩子的 this 可以正确访问到组件实例,所有没有必要使用回调。
最后是完整的导航解析流程:
- 导航被触发
- 在失活的组件里调用离开守卫
- 调用全局的 beforeEach 守卫
- 在重用的组件里调用 beforeRouteUpdate 守卫
- 在路由配置里调用 beforEnter
- 解析异步路由组件
- 在被激活的组件里调用 beforeRouteEnter
- 调用全局的 beforeResolve 守卫
- 导航被确认
- 调用全局的 afterEach 钩子
- 触发 DOM 更新
- 在创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数