Vue Router 导航守卫:避免多次执行的陷阱与解决方案

2023-12-12 17:10:39 浏览数 (3)

导语: Vue Router 是 Vue.js 官方提供的路由器,它用于处理单页应用(SPA)中的路由导航。在 Vue Router 中,导航守卫是非常重要的功能,它可以在路由跳转之前或之后执行一些特定的操作。但是,如果你不小心,导航守卫可能会多次执行,这可能会导致一些问题。本文将介绍如何避免导航守卫多次执行,并提供解决方案。

导航守卫的基本概念

在 Vue Router 中,导航守卫分为四个阶段:beforeEach、beforeEnter、afterEach 和 afterEnter。它们分别在导航开始、进入路由组件、导航完成和路由组件加载完成后执行。

  • beforeEach:在每条路由的进入之前执行,且仅对当前路由有效。
  • beforeEnter:在进入路由组件之前执行,且仅对当前路由有效。
  • afterEach:在每条路由的完成之后执行,且仅对当前路由有效。
  • afterEnter:在路由组件加载完成之后执行,且仅对当前路由有效。

避免多次执行的陷阱

有时,我们需要在路由守卫中执行一些操作,例如检查用户是否已登录。如果我们在每个路由的 beforeEach 守卫中执行这个操作,就可能会出现问题。因为每次导航时,都会执行 beforeEach 守卫,即使路由没有改变,也会重新执行。这就导致了操作被多次执行,可能会导致一些问题。

举个例子,假设我们在 beforeEach 守卫中检查用户是否登录,如果未登录,则跳转到登录页面。如果用户在登录页面已经登录,但未完成登录操作就关闭了页面,再次打开页面时,由于 beforeEach 守卫会多次执行,会导致用户再次被重定向到登录页面,这就不是我们想要的结果。

实际项目中的陷阱

举例:

代码语言:javascript复制
...省略代码

router.afterEach((to, from) => {
  if (to.path !== from.path) {
// 这里发送了某次接口请求
    axios.get('xxxx')
  }
});

...省略代码

onMounted(() => {
//
})

如果我们切换组件,再次初始化这个组件,会导致这个axios.get('xxxx') 这个方法被调用多次。

原因: 在 Vue Router 中,当你使用 router.afterEach 添加一个全局导航守卫时,这个导航守卫会被存储在 Vue Router 的内部实例中。当路由发生变化时,Vue Router 会从内部实例中获取这些导航守卫,并在适当的时机执行它们。

具体来说,当你在组件中使用 router.afterEach 时,这个导航守卫会被添加到 Vue Router 的全局配置中,而不是存储在组件的调用栈中。因此,即使组件被销毁,这个导航守卫仍然会保留在 Vue Router 的内部实例中,并在下一次路由变化时继续执行。

总之,全局导航守卫不会存储在组件的调用栈中,而是存储在 Vue Router 的内部实例中。这就是为什么在组件被销毁后,导航守卫仍然会继续执行的原因。

提供解决方案(举例)

为了避免导航守卫多次执行,我们可以采用以下两种方法:

重点: 在全局使用统一的拦截,不要在组件中使用,避免导致在组件中使用,组件被销毁,实际上拦截器上的函数是不会被销毁的,当你再次初始化时,这时会导致意外的执行两次、多次

1. 使用 router.afterEach(() => { ... })

在 afterEach 守卫中执行操作可以避免多次执行的问题。因为 afterEach 守卫只在导航完成之后执行,无论路由是否改变。

例如,我们可以将用户登录检查操作放在 afterEach 守卫中:

代码语言:javascript复制
router.afterEach(() => {
  if (!loginStatus) {
    router.replace('/login')
  }
})

在这个例子中,afterEach 守卫在每条路由完成之后执行,如果用户未登录,则使用 router.replace() 方法将用户重定向到登录页面。这样,无论用户如何导航,只要他们未登录,他们就会被重定向到登录页面,避免了导航守卫多次执行的问题。

2. 使用 router.beforeRouteLeave(to, from, next)

另一个避免导航守卫多次执行的方法是使用 beforeRouteLeave 守卫。它只对即将离开的路由有效,因此可以避免在进入路由组件之前多次执行操作。

例如,我们可以在 beforeRouteLeave 守卫中检查用户是否登录:

代码语言:javascript复制
router.beforeRouteLeave((to, from, next) => {
  if (!loginStatus) {
    next('/login')
  } else {
    next()
  }
})

在这个例子中,beforeRouteLeave 守卫在即将离开当前路由之前执行,如果用户未登录,则使用 next('/login') 方法将用户重定向到登录页面。这样,无论用户如何导航,只要他们未登录,他们就会被重定向到登录页面,避免了导航守卫多次执行的问题。

总结

在 Vue Router 中,导航守卫是非常有用的功能,但它可能会导致多次执行的问题。为了避免这个问题,我们可以使用 router.afterEach(() => { ... })router.beforeRouteLeave((to, from, next) => { ... }) 方法来避免多次执行。根据你的具体情况选择合适的方法,使你的应用更加稳定和可靠。

我正在参与2023腾讯技术创作特训营第四期有奖征文,快来和我瓜分大奖!

0 人点赞