路由守卫是什么?
官方解释:
"导航"表示路由正在发生改变。vue-router提供的导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。
导航守卫就是路由跳转过程中的一些钩子函数。 路由跳转是一个大的过程,这个大的过程分为跳转前中后等等细小的过程,在每一个过程中都有一函数,这个函数能让你操作一些其他的事,这就是导航守卫。类似于Vue
的生命周期钩子函数。
路由守卫的分类
路由守卫有多种类别,大致可以分为全局的,单个路由独享的,或者组件级的。以下是这几种类别的区别。
-
全局守卫:是指路由实例上直接操作的钩子函数,特点是所有路由配置的组件都会触发,直白点就是触发路由就会触发这些钩子函数
-
路由守卫:是指在单个路由配置的时候也可以设置的钩子函数
-
组件守卫: 是指在组件内执行的钩子函数,类似于组件内的生命周期,相当于为配置路由的组件添加的生命周期钩子函数。
路由守卫中回调函数的参数
每个守卫方法接收三个参数:
to
: 即将要进入的目标from
: 当前导航正要离开的路由- next :涉及到next参数的钩子函数,必须调用next()方法来resolve这个钩子,否则路由会中断在这,不会继续往下执行。注意,这个参数是可选的。
路由守卫详解
全局路由守卫
守卫 | 函数 | 说明 | 功能 |
---|---|---|---|
全局前置守卫 | beforeEach |
在路由改变之前 | 鉴权,登录状态核对,打点等相关操作 |
全局解析守卫 | beforeResolve |
在导航被确认之前 1. 所有的组件内守卫执行完毕 2. 异步路由组件已经解析完成 | beforeResolve 方法可以确保路由组件及组件内回调被执行完成后再执行渲染 可以避免在渲染页面之前异步组件还未加载完成的情况 所以这个回调更多的是vue内部被回调 |
全局后置钩子 | afterEach |
在路由跳转完成后执行的回调 注意: 此时导航已经完成,无法通过这个回调来改变导航 所以它不是守卫函数,只是一个钩子函数 | 比如页面滚动到指定位置、更新页面标题等 |
全局前置守卫
js
// 全局前置守卫
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) {
next({ name: 'Login' })
}
else next()
}
)
全局解析守卫
js
router.beforeResolve(async to => {
if (to.meta.requiresCamera) {
try {
await askForCameraPermission()
} catch (error) {
if (error instanceof NotAllowedError) {
// ... 处理错误,然后取消导航
return false
} else {
// 意料之外的错误,取消导航并把错误传给全局处理器
throw error
}
}
}
})
全局后置钩子
和守卫不同的是,全局后置钩子不会接受 next
函数也不会改变导航本身:
js
router.afterEach((to, from) => {
sendToAnalytics(to.fullPath)
})
路由独享守卫
beforeEnter
是路由独享守卫,该守卫只有在进入路由时触发,不会在 params
、query
或 hash
改变时触发
js
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: (to, from) => {
// reject the navigation
return false
},
},
]
也可以将一个函数数组传递给 beforeEnter
以方便在不同路由中复用守卫函数
js
// 在本例中removeQueryParams被复用了两次
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: [removeQueryParams, removeHash],
},
{
path: '/about',
component: UserDetails,
beforeEnter: [removeQueryParams],
},
]
组件内守卫
组件内守卫指的是在路由组件
内直接定义的导航守卫函数。 也就是说组件内守卫只能在路由组件中使用,在渲染到<router-view />
的子组件中是不存在组件内守卫的。
守卫 | 说明 |
---|---|
beforeRouteEnter |
异步组件加载完毕,组件实例化之前 不可以访问组件实例 this |
beforeRouteUpdate |
当前路由改变,但是该组件被复用时调用 如/users/1 和 /users/2 之间之间进行跳转的时候 可以访问组件实例 this |
beforeRouteLeave |
离开该组件的时候 可以访问组件实例 this |
beforeRouteEnter
beforeRouteEnter
是唯一一个支持给 next
传递回调的守卫
js
beforeRouteEnter(to, from) {
// 在渲染该组件的对应路由被验证前调用
// 不能获取组件实例 `this` !
// 因为当守卫执行时,组件实例还没被创建!
},
beforeRouteUpdate
在当前路由改变时,并且该组件被复用时调用,可以通过this访问实例。
js
beforeRouteUpdate(to, from) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 `/users/:id`,在 `/users/1` 和 `/users/2` 之间跳转的时候,
// 由于会渲染同样的 `UserDetails` 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 因为在这种情况发生的时候,组件已经挂载好了,导航守卫可以访问组件实例 `this`
},
beforeRouteLeave
离开守卫 通常用来预防用户在离开界面时没有保存修改
js
beforeRouteLeave (to, from) {
const answer = window.confirm('是否确认离开')
// 通过返回false,来取消离开操作
if (!answer) return false
}
完整的导航解析流程
- 导航被触发。
- 在失活的组件里调用
beforeRouteLeave
守卫。 - 调用全局的
beforeEach
守卫。 - 在重用的组件里调用
beforeRouteUpdate
守卫。 - 在路由配置里调用
beforeEnter
。 - 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter
。 - 调用全局的
beforeResolve
守卫。 - 导航被确认。
- 调用全局的
afterEach
钩子。 - 触发 DOM 更新。
- 调用
beforeRouteEnter
守卫中传给next
的回调函数,创建好的组件实例会作为回调函数的参数传入。