项目场景:
路由跳转控制台提示:Uncaught (in promise) Error: Navigation cancelled from "/" to "/login" with a new navigation.
通常是因为在路由跳转过程中,某个导航被取消了。
如果你的应用中在用户未满足某些条件时(比如未登录时尝试访问需要认证的页面、token过期),会立即重定向到登录页面,而在这个过程中如果用户或代码再次触发了路由跳转,就可能导致这个错误。
原因分析:
报错原因:
- 异步路由守卫:你可能在路由守卫(如 beforeEach 或 beforeRouteEnter)中进行了异步操作,但没有正确处理这些 Promise 的结果,导致导航过程中途被取消。
- 重复导航:可能在同一个导航中触发了多次路由跳转,比如手动调用 this.$router.push() 或者在导航完成之前又触发了新的导航。
- 导航拦截:当在路由守卫中进行条件判断时,如果没有正确处理条件跳转(如 next(false)、next(‘/’) 或 next({ path: ‘/login’ })),可能会引发导航被取消的错误。
解决方案:
方法一:
捕获导航取消的 Promise: 在 Vue Router 中,导航失败通常会返回一个 rejected 的 Promise,因此可以捕获这个错误。你可以在跳转时使用 .catch() 来避免报错。
this.$router.push('/login').catch(err => {});
方法二:
检查路由守卫中的逻辑: 确保在 beforeEach 等路由守卫中,没有引发意外的导航取消。如果你的守卫中使用了异步操作,请确保正确处理异步逻辑:
router.beforeEach(async (to, from, next) => {
try {
// 异步逻辑,例如获取用户信息
await someAsyncFunction();
next(); // 导航成功
} catch (error) {
next(false); // 取消导航
}
});
方法三:
避免重复导航: 如果你在代码中手动触发了多次相同的路由跳转(比如连续多次 this.$router.push(‘/login’)),Vue Router 会认为是重复导航并取消后续导航操作。你可以先检查当前路由是否已经是目标路由,再决定是否跳转。
if (this.$route.path !== '/login') {
this.$router.push('/login');
}
方法四:(本人直接采用的第四种方法解决,懒得重复写catch和检查逻辑了)
通过自定义配置忽略导航错误: 如果不希望这些错误出现在控制台中,你可以全局忽略导航取消的错误,直接重新router原型上的push方法和replace 方法用catch捕获错误
const originalPush = Router.prototype.push;
const originalReplace = Router.prototype.replace;
// push
Router.prototype.push = function push(location, onResolve, onReject) {
if (onResolve || onReject)
return originalPush.call(this, location, onResolve, onReject);
return originalPush.call(this, location).catch(err => err);
};
//replace
Router.prototype.replace = function push(location, onResolve, onReject) {
if (onResolve || onReject)
return originalReplace.call(this, location, onResolve, onReject);
return originalReplace.call(this, location).catch(err => err);
};