跳至内容

等待导航结果

使用 router-link 时,Vue Router 会调用 router.push 来触发导航。虽然大多数链接的预期行为是将用户导航到新页面,但有一些情况会导致用户停留在同一页面

  • 用户已经位于他们试图导航到的页面。
  • 一个 导航守卫 通过执行 return false 来中止导航。
  • 一个新的导航守卫在之前的导航守卫未完成时发生。
  • 一个 导航守卫 通过返回一个新的位置来重定向到其他地方(例如 return '/login')。
  • 一个 导航守卫 抛出一个 Error

如果我们想在导航完成后做一些事情,我们需要一种在调用 router.push 后等待的方法。想象一下,我们有一个移动菜单,它允许我们转到不同的页面,我们只想在导航到新页面后隐藏菜单,我们可能想要做这样的事情

js
router.push('/my-profile')
this.isMenuOpen = false

但这会立即关闭菜单,因为 导航是异步的,我们需要 await router.push 返回的 Promise

js
await router.push('/my-profile')
this.isMenuOpen = false

现在菜单将在导航完成后关闭,但如果导航被阻止,它也会关闭。我们需要一种方法来检测我们是否真的从当前页面导航走了。

检测导航失败

如果导航被阻止,导致用户停留在同一页面,则 router.push 返回的 Promise 的解析值将是一个 导航失败。否则,它将是一个 假值(通常是 undefined)。这使我们能够区分我们是否从当前页面导航走了

js
const navigationResult = await router.push('/my-profile')

if (navigationResult) {
  // navigation prevented
} else {
  // navigation succeeded (this includes the case of a redirection)
  this.isMenuOpen = false
}

导航失败Error 实例,它具有几个额外的属性,这些属性提供了足够的信息来了解哪些导航被阻止以及原因。要检查导航结果的性质,请使用 isNavigationFailure 函数

js
import { NavigationFailureType, isNavigationFailure } from 'vue-router'

// trying to leave the editing page of an article without saving
const failure = await router.push('/articles/2')

if (isNavigationFailure(failure, NavigationFailureType.aborted)) {
  // show a small notification to the user
  showToast('You have unsaved changes, discard and leave anyway?')
}

提示

如果你省略第二个参数:isNavigationFailure(failure),它只会检查 failure 是否是一个 导航失败

你可以通过使用 router.afterEach() 导航守卫 来全局检测全局导航失败

ts
router.afterEach((to, from, failure) => {
  if (failure) {
    sendToAnalytics(to, from, failure)
  }
})

区分导航失败

正如我们在一开始所说,有不同的情况会导致导航中止,所有这些情况都会导致不同的 导航失败。它们可以使用 isNavigationFailureNavigationFailureType 来区分。有三种不同的类型

  • aborted:在导航守卫中返回 false 来阻止导航。
  • cancelled:在当前导航完成之前发生了新的导航。例如,在导航守卫中等待时调用了 router.push
  • duplicated:导航被阻止,因为我们已经位于目标位置。

所有导航失败都公开 tofrom 属性,以反映当前位置以及失败导航的目标位置

js
// trying to access the admin page
router.push('/admin').then(failure => {
  if (isNavigationFailure(failure, NavigationFailureType.aborted)) {
    failure.to.path // '/admin'
    failure.from.path // '/'
  }
})

在所有情况下,tofrom 都是规范化的路由位置。

检测重定向

在导航守卫中返回一个新的位置时,我们会触发一个新的导航,它会覆盖正在进行的导航。与其他返回值不同,重定向不会阻止导航,它会创建一个新的导航。因此,它通过读取路由位置中的 redirectedFrom 属性来进行不同的检查

js
await router.push('/my-profile')
if (router.currentRoute.value.redirectedFrom) {
  // redirectedFrom is resolved route location like to and from in navigation guards
}