Vue 教程(四十五)Vue 导航守卫

Posted _否极泰来_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue 教程(四十五)Vue 导航守卫相关的知识,希望对你有一定的参考价值。

Vue 教程(四十五)Vue 导航守卫

什么是导航守卫

“导航”表示路由正在发生变化

导航守卫表示当导航开始变化到导航变化结束的那段时间里,根据导航的变化做出一些响应。比如要跳转到一个页面时,看他是不是登录了,没登录的话,得让他先登录。主要是通过跳转到某处或者取消跳转来守卫导航。

Vue Router 提供的导航

Vue Router 提供的导航守卫主要用来监听监听路由的进入和离开的。

Vue Router 提供了 beforeEach 和 afterEach 的钩子函数,它们会在路由即将改变前和改变后触发。

  • 修改标题需求

    在一个 SPA 应用中,点击不同按钮、切换页面时,修改跳转页面对应的标题,可以通过 javascript 来修改 <title> 的内容。

    如果页面比较多时,在每一个路由对应的组件 .vue 文件中,通过 created 声明周期函数, 执行对应的代码进行修改,这种方式维护成本太高,下面通过导航守卫的方式实现

添加元属性

// 2. 定义路由
const routes = [
  {
    // 配置默认路径
    path: '/',
    redirect: '/home',
  },
  {
    meta: { title: '首页' },
    path: '/home',
    component: () => import('../components/Home'),
    children: [
      {
        meta: { title: '新闻' },
        path: 'news',
        component: () => import('../components/News'),
      },
    ],
  },
  {
    meta: { title: '关于' },
    path: '/about',
    component: () => import('../components/About'),
  },
  {
    meta: { title: '分类' },
    path: '/category/:categoryId',
    component: () => import('../components/Category'),
  },
  {
    meta: { title: '用户' },
    path: '/user',
    component: () => import('../components/User'),
  },
]

全局守卫

  • 全局前置守卫

    可以使用 router.beforeEach 注册一个全局前置守卫

    // 前置钩子(guard)
    router.beforeEach((to, from, next) => {
      // 设置当前标题为:要跳转页面匹配的第一个路径meta元素的标题
      window.document.title = to.matched[0].meta.title
      // next函数:调用该方法后,才能进入下一步
      next()
    })
    

每个守卫方法接收三个参数:

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 函数在任何给定的导航守卫中都被严格调用一次。它可以出现多于一次,但是只能在所有的逻辑路径都不重叠的情况下,否则钩子永远都不会被解析或报错。

  • 全局后置守卫

    可以使用 afterEach 注册全局后置钩子 ,但不需要主动调用 next() 函数。

记录用户操作日志:

// 全局后置守卫(hook)
router.afterEach((to, from) => {
  console.log('操作历史:', from.meta.title + '===>' + to.meta.title)
})

路由独享的守卫

你可以在路由配置上直接定义 beforeEnter 守卫,只有当进入这个路由时才会调用的,这些守卫与全局前置守卫的方法参数是一样的。

const routes = [
  {
    // 配置默认路径
    path: '/',
    redirect: '/home',
  },
  {
    meta: { title: '首页' },
    path: '/home',
    component: () => import('../components/Home'),
    children: [
      {
        meta: { title: '新闻' },
        path: 'news',
        component: () => import('../components/News'),
      },
    ],
  },
  {
    meta: { title: '关于' },
    path: '/about',
    component: () => import('../components/About'),
    beforeEach: (to, from, next) => {
      // ...
    },
  },
  {
    meta: { title: '分类' },
    path: '/category/:categoryId',
    component: () => import('../components/Category'),
  },
  {
    meta: { title: '用户' },
    path: '/user',
    component: () => import('../components/User'),
  },
]

组件内的守卫

你可以在路由组件内直接定义以下路由导航守卫:

  • beforeRouteEnter
  • beforeRouteUpdate (2.2 新增)
  • beforeRouteLeave
const Foo = {
  template: `...`,
  beforeRouteEnter(to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
  },
  beforeRouteUpdate(to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
  },
  beforeRouteLeave(to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  },
}

这三个守卫是写在组件里,beforeRouteEnter 守卫不能访问 this,因为守卫在导航确认前被调用,因此即将进入的新组件还没被创建。

不过,你可以通过传一个回调给 next 来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。其他两个都可以用 this。

beforeRouteEnter (to, from, next) {
   next(vm => {
     // 通过 `vm` 访问组件实例
   })
 }

这个离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过 next(false) 来取消。

beforeRouteLeave (to, from, next) {
   const answer = window.confirm('有未保存的更改,你真的想离开吗?')
   if (answer) {
     next()
   } else {
     next(false)
   }
 }

完整的导航解析流程

  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 的回调函数,创建好的组件实例会作为回调函数的参数传入。

    – 以上为《Vue 教程(四十五)Vue 导航守卫》,如有不当之处请指出,我后续逐步完善更正,大家共同提高。谢谢大家对我的关注。

——厚积薄发(yuanxw)

以上是关于Vue 教程(四十五)Vue 导航守卫的主要内容,如果未能解决你的问题,请参考以下文章

vue源码 | 导航守卫的整体逻辑

Vue 导航守卫

vue导航守卫和axios拦截器的区别

Vue 教程(四十九)Vuex 核心概念和项目结构

Vue 教程(四十九)Vuex 核心概念和项目结构

Vue 教程(四十九)Vuex 核心概念和项目结构