Vue Router(9)

导航守卫

正如其名,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。

 

全局的前置守卫

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

const router = createRouter({ ... })

router.beforeEach((to, from) => {
  // ...
  // 返回 false 以取消导航
  return false
})

 

当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫resolve完之前一直处于等待中。

 

每个守卫方法接受两个参数:

   to: 即将要进入的目标

   from:当前导航正要离开的路由

 

全局解析守卫

你可以用就 router.beforeResolve 注册一个全局守卫。 这和 router.beforeEach 类似, 因为它在每次导航时都会触发,但是确保在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被正确调用。这里有一个例子,确保用户可以访问自定义meta熟悉 requiresCamera 的路由:

router.beforeResolve(async to => {
  if (to.meta.requiresCamera) {
    try {
      await askForCameraPermission()
    } catch (error) {
      if (error instanceof NotAllowedError) {
        // ... 处理错误,然后取消导航
        return false
      } else {
        // 意料之外的错误,取消导航并把错误传给全局处理器
        throw error
      }
    }
  }
})

router.beforeResolve 是获取数据或执行任何其他操作(如果用户无法进入页面时你希望避免执行的操作)的理想位置。

 

全局后置钩子

你也可以注册全局后置钩子,然而和守卫不同的是,这戏狗子不会接受next函数也不hi改变导航本身:

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

它们对于分析、更改页面标题、声明页面等辅助功能以及许多其他事情都很有用。

 

路由独享的守卫

你可以直接在路由配置上定义 beforeEnter 守卫

const routes = [
  {
    path: '/users/:id',
    component: UserDetails,
    beforeEnter: (to, from) => {
      // reject the navigation
      return false
    },
  },
]

beforeEnter 守卫 只在进入路由时触发, 不会在 params、Query、或 hash改变时触发。

 

可以将一个函数数组传递给 beforeEnter, 这在为不同的路由重用守卫时很有用

function removeQueryParams(to) {
  if (Object.keys(to.query).length)
    return { path: to.path, query: {}, hash: to.hash }
}

function removeHash(to) {
  if (to.hash) return { path: to.path, query: to.query, hash: '' }
}

const routes = [
  {
    path: '/users/:id',
    component: UserDetails,
    beforeEnter: [removeQueryParams, removeHash],
  },
  {
    path: '/about',
    component: UserDetails,
    beforeEnter: [removeQueryParams],
  },
]

 

组件内的守卫

beforeRouteEnter

beforeRouteUpdate

beforeRouteLeave

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

 

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

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

注意 beforeRouteEnter 是支持给 next 传递回调的唯一守卫。对于 beforeRouteUpdate 和 beforeRouteLeave 来说,this 已经可用了,所以不支持传递回调,因为没有必要了

beforeRouteUpdate

beforeRouteUpdate (to, from) {
  // just use `this`
  this.name = to.params.name
}

 

beforeRouteLeave

这个离开守卫 通常用来预防用户在还未保存修改前突然离开,该导航可以通过返回false来取消

beforeRouteLeave (to, from) {
  const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
  if (!answer) return false
}

 

完整的导航解析流程

1、导航被触发

2、在失活的组件里调用 beforeRouteLeave 守卫

3、调用全局的 beforeEach 守卫

4、在重用的组件里调用 beforeRouteUpdate 守卫

5、在路由配置里调用 beforeEnter

6、解析异步路由组件

7、在被激活的组件里调用 beforeRouteEnter

8、调用全局的 beforeResolve 守卫

9、导航被确认

10、调用全局的 afterEach 钩子

11、触发 DOM 更新

12、调用 beforeRouteEnter 守卫中传给next的回调函数, 创建好的组件实例会作为回调函数的参数传入。

上一篇:vue-cli2 单个组件打包为js


下一篇:Leetcode算法——553. 最优除法