1、什么是导航守卫?

2,024 阅读4分钟

个人理解:

  • 在进行路由切换的过程就是导航;
  • 设置导航,就在切换过程中进行限制,限制执行了,就是守卫成功了;
以下结合各路大神的总结,望海涵。

一、导航守卫的分类

1、有3种导航守卫

  • 全局守卫
  • 单个路由独享守卫
  • 组件内的守卫

2、都有3个参数,除了 afterEach守卫(后面详解)

  • to: 要进入的目标路由
  • from: 离开当前的路由
  • next: 控制路由执行(必须要有),一定要调用该方法来 resolve 这个钩子

3、next 4个行为:

next();  // 钩子执行完了,可以进入下一个路由;导航守卫的状态:confirmed
next(false); //中断当前路由跳转行为
next('/'); next({ path: '/' }) // 根据路由跳转条件来进入相应的路由,进入一个新的导航
next( new Error ) // 中断路由,错误会被传递给 router.onError() 注册过的回调中

二、3种导航守卫详解

1、全局路由守卫(有3个)

  • 挂载到 router 实例上
  • 用于控制路由的每一次跳转

1.1、beforeEach:全局前置守卫

const router = new VueRouter({ ... })

router.beforeEach((to, from, next) => {
  // to 代表去的路由 a => b  b就是去的路由
  // from 代表来自于哪个路由 a => b  a就是来自的路由
  // next 控制路由的跳转与取消跳转
      // 不加上 next ,页面跳转不了
      // next() 执行跳转
      // next(false) 取消跳转 a => b
      // next 重新定向到某个页面 next("/login")
})

作用: 常用于登录验证

router.beforeEach((to, from, next) => {
  if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
  else next()
})

1.2、beforeResolve:全局解析守卫

你可以用 router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。

1.3、afterEach:全局后置钩子守卫

这些钩子不会接受 next 函数也不会改变导航本身:

router.afterEach((to, from) => {
  // ...
})

2、单个路由独享守卫(1个)

2.1、 beforeEnter

可以在路由配置上直接定义 beforeEnter 守卫;只有进入到当前页面才会执行的守卫函数;

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})

3、组件内的守卫(3个)

3.1、beforeRouteEnter

  • 在渲染该组件的对应路由被 confirm 前调用(大概意思:进入之前调用);
  • 重点:不能获取 this 实例。因为当守卫执行前,组件实例还没被创建;
  • 顺序:beforeEach 和 独享守卫 beforeEnter 之后,全局 beforeResolve 和 afterEach 之前调用;
const Foo = {
  template: `...`,
  beforeRouteEnter(to, from, next) {
  },
 }
  • 解决: beforeRouteEnter 守卫 不能 访问 this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。
beforeRouteEnter (to, from, next) {
  next(vm => {
    // 通过 `vm` 访问组件实例
  })
}

3.2、beforeRouteUpdate

  • 在当前路由改变,但是该组件被复用时调用;
  • 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用;
  • 可以访问组件实例 this
const Foo = {
  template: `...`
  beforeRouteUpdate(to, from, next) {
  },
 }

3.3、beforeRouteLeave

  • 导航离开该组件的对应路由时调用
  • 可以访问组件实例 this
beforeRouteLeave(to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  }

beforeRouteLeave 使用场景:

  1. 当组件内有定时器,需要清除时,路由切换以免导致内存占用;
  2. 将公用信息保存到 session 或 vuex 中;
  3. 当页面有未关闭的窗口,或有未保存的时候,该导航可以通过 next(false) 来取消阻止页面跳转,示例如下:
beforeRouteLeave (to, from, next) {
  const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
  if (answer) {
    next()
  } else {
    next(false)
  }
}

4、完整的导航解析

  1. 导航被触发。
  2. 在失活的组件里调用 beforeRouteLeave 守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
  5. 在路由配置里调用 beforeEnter
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter
  8. 调用全局的 beforeResolve 守卫 (2.5+)。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

路由守卫.jpg