项目中vue-router升级到3.1.x版本后, 在路由跳转通过编程式时控制台如有如下错误:
- 链接: jsrun.pro/KuWKp/edit
- 复现步骤:
- 启用vue-router@3.1.x脚本引用, 并打开浏览器控制台
- 点击两次Go to foo 按钮(多次使用
$router.replace或$router.push跳转到同一地址)
关于这个问题, vuejs成员posva已经在No stacktrace on NavigationDuplicated error中进行说明.
我们来看下他都说了啥:
- 3.1.x 版本之前, 在调用
router.push方法时没有提供回调, 错误会被发送至全局错误处理方法( global router error handler), 3.1.x版本之后, 调用push或replace会返回一个promise, 如果导航失败(任何导航取消比如next(false)或next('/other')都算在内)没有被捕获, 你都会在控制台看到这个错误, 这是因为promise的rejection没有被捕获, 因此, 当我们尝试导航到与当前位置相同的路由时这个错误就会出现(路由不需要跳转, 所以orimise处于rejected状态, 而错误有没有手动处理) - 过编程式导航来进行路由跳转时我们可以通过捕获rejection来忽略该错误.
router.push('/location', () => {}) - 如果不关心导航失败,则应该使用catch来捕获它:
router.push('/location').catch(err => {}) - 因为Promise api可能会成为默认api,而回调版本会被弃用。
- 这不是一个破坏性改动(因为代码仍能够正常运行), 只是有以下使用方式时会有错误提示:
return router.push('/location') // this is now returning the promise
await router.push('/location') // this explicitely awaits for the navigation to be finished
- 3.1 版本之前
router.push不会返回任何内容, 所以上述使用方法属于无效的用例(3.1之前). 3.1之后, 它们是可行的,但是也会在暴露以前不可见的错误. - 如果要全局处理, 可以通过修改Router原型链上的replace, push方法来避免出现该错误.
['push', 'replace'].forEach(method => {
const prototypeMethod = Router.prototype[method];
Router.prototype[method] = function(location, onResolve, onReject) {
if (onResolve || onReject) return prototypeMethod.call(this, location, onResolve, onReject);
return prototypeMethod.call(this, location).catch(err => err);
};
});