导语: 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腾讯技术创作特训营第四期有奖征文,快来和我瓜分大奖!