在 Vue.js 中,Vue Router 提供了一系列的路由守卫(navigation guard),用于在路由切换过程中进行拦截和控制,以满足不同的业务需求。
Vue Router 的路由守卫主要分为三类:
除了全局路由守卫
之外,Vue Router 还提供了路由独享守卫
和组件内的守卫
。其中,路由独享守卫是针对某个具体的路由实例进行拦截和控制,而组件内的守卫则是针对某个具体的组件进行拦截和控制。
Vue Router 的全局路由守卫主要分为三类:
全局前置守卫是 Vue Router 中最常用的路由守卫之一。它会在路由切换之前进行拦截和控制,以满足不同的业务需求。全局前置守卫的使用方法如下:
const router = new VueRouter({
routes: [
// ...
]
})
router.beforeEach((to, from, next) => {
// ...
})
在全局前置守卫中,我们可以访问到即将要进入的路由对象 to
,以及当前的路由对象 from
。另外,还可以通过 next
函数控制路由的跳转行为。如果调用 next
函数并传入一个路由对象,则会跳转到该路由。如果不调用 next
函数,则当前路由不会发生变化。
router.beforeEach((to, from, next) => {
if (to.path === '/login') {
next()
} else {
if (isLogin()) {
next()
} else {
next('/login')
}
}
})
在上面的例子中,我们判断了即将要进入的路由是否为登录页。如果是登录页,则直接跳转到该路由。如果不是登录页,则判断用户是否已经登录。如果已经登录,则跳转到该路由;如果未登录,则跳转到登录页。
全局解析守卫是在路由解析之前进行拦截和控制
的,它会在所有全局前置守卫 resolve 完成之后被调用。全局解析守卫的使用方法与全局前置守卫类似:
router.beforeResolve((to, from, next) => {
// ...
})
在全局解析守卫中,我们同样可以访问到即将要进入的路由对象 to
,以及当前的路由对象
全局后置守卫 afterEach
会在每次路由跳转结束后被调用,无论是正常跳转还是取消跳转
。它接收三个参数:
我们可以通过 afterEach
钩子做一些全局的收尾工作,例如埋点、页面滚动等操作。
router.afterEach((to, from) => {
// 埋点
trackPage(to.path)
// 页面滚动到顶部
window.scrollTo(0, 0)
})
需要注意的是,afterEach
钩子不像其他路由钩子一样,不能通过调用 next
函数来控制路由的跳转行为,因为此时路由跳转已经结束了。如果在 afterEach
钩子中调用 next
函数,则会抛出一个错误。
javascript
// 会抛出一个错误
router.afterEach((to, from, next) => {
// ...
next()
})
路由独享守卫 beforeEnter
路由独享守卫是针对某个具体的路由实例进行拦截和控制
。它和全局前置守卫的用法类似,只不过它是针对某个具体的路由实例而言的。
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
在路由独享守卫中,我们同样可以访问到即将要进入的路由对象 to,以及当前的路由对象 from。另外,还可以通过 next 函数控制路由的跳转行为。如果调用 next 函数并传入一个路由对象,则会跳转到该路由。如果不调用 next 函数,则当前路由不会发生变化
组件内的守卫是针对某个具体的组件进行拦截和控制。它分为三种:
这三个守卫的使用方法如下:
export default {
beforeRouteEnter (to, from, next) {
// ...
},
beforeRouteUpdate (to, from, next) {
// ...
},
beforeRouteLeave (to, from, next) {
// ...
}
}
在组件内的守卫中,我们同样可以访问到即将要进入的路由对象 to,以及当前的路由对象 from。另外,还可以通过 next 函数控制路由的跳转行为。如果调用 next 函数并传入一个路由对象,则会跳转到该路由。如果不调用 next 函数,则当前路由不会发生变化。
需要注意的是,由于在 beforeRouteEnter 钩子中访问不到组件实例 this,所以在该钩子中无法访问到组件实例的数据和方法。如果需要访问组件实例的数据和方法,可以使用 next(vm => {}) 传入一个回调函数,在回调函数中访问组件实例。
export default {
beforeRouteEnter (to, from, next) {
next(vm => {
console.log(vm.message)
})
}
}