相关文章推荐
神勇威武的拐杖  ·  【認識德國各邦2 ...·  10 月前    · 
调皮的番茄  ·  TicWatch Pro ...·  1 年前    · 
Skip to content
Vue Router
本页内容

导航守卫

正如其名,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。这里有很多方式植入路由导航中:全局的,单个路由独享的,或者组件级的。

全局前置守卫

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

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

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

可以返回的值如下:

  • false : 取消当前的导航。如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
  • 一个 路由地址 : 通过一个路由地址跳转到一个不同的地址,就像你调用 router.push() 一样,你可以设置诸如 replace: true name: 'home' 之类的配置。当前的导航被中断,然后进行一个新的导航,就和 from 一样。

如果遇到了意料之外的情况,可能会抛出一个 Error 。这会取消导航并且调用 router.onError() 注册过的回调。

如果什么都没有, undefined 或返回 true 则导航是有效的 ,并调用下一个导航守卫

以上所有都同 async 函数 和 Promise 工作方式一样:

可选的第三个参数 next

在之前的 Vue Router 版本中,也是可以使用 第三个参数 next 的。这是一个常见的错误来源,可以通过 RFC 来消除错误。然而,它仍然是被支持的,这意味着你可以向任何导航守卫传递第三个参数。在这种情况下, 确保 next 在任何给定的导航守卫中都被 严格调用一次 。它可以出现多于一次,但是只能在所有的逻辑路径都不重叠的情况下,否则钩子永远都不会被解析或报错。这里有一个在用户未能验证身份时重定向到 /login 错误用例

下面是正确的版本:

全局解析守卫

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

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

全局后置钩子

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

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

它们也反映了 navigation failures 作为第三个参数:

了解更多关于 navigation failures 的信息在 它的指南 中。

路由独享的守卫

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

beforeEnter 守卫 只在进入路由时触发 ,不会在 params query hash 改变时触发。例如,从 /users/2 进入到 /users/3 或者从 /users/2#info 进入到 /users/2#projects 。它们只有在 从一个不同的 路由导航时,才会被触发。

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

请注意,你也可以通过使用 路径 meta 字段 全局导航守卫 来实现类似的行为。

组件内的守卫

最后,你可以在路由组件内直接定义路由导航守卫(传递给路由配置的)

可用的配置 API

你可以为路由组件添加以下配置:

  • beforeRouteEnter
  • beforeRouteUpdate
  • beforeRouteLeave

beforeRouteEnter 守卫 不能 访问 this ,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。

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

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

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