1.第一部分 通过源码分析报错原因
vue-router v3.1.0版本以后就会存在对性能优化,抛错处理。
例如使用this.$router.push(‘/list’) 重复跳转 就会报错:
overlay.js:2065 Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location: "/list".
at createRouterError (http://localhost:8080/main.js:31179:15)
at createNavigationDuplicatedError (http://localhost:8080/main.js:31149:15)
at HTML5History.confirmTransition (http://localhost:8080/main.js:31447:18)
at HTML5History.transitionTo (http://localhost:8080/main.js:31374:8)
at HTML5History.push (http://localhost:8080/main.js:31720:10)
at http://localhost:8080/main.js:32148:22
at new Promise ()
at VueRouter.push (http://localhost:8080/main.js:32147:12)
at VueComponent.created
查看源码先看看push做了啥
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
const { current: fromRoute } = this
this.transitionTo(
location,
route => {
pushHash(route.fullPath)
handleScroll(this.router, route, fromRoute, false)
onComplete && onComplete(route)
},
onAbort
)
}
push方法内部调用了transitionTo方法,而transitionTo内部又调用confirmTransition方法来优化处理重复访问同一个路由。transitionTo方法省略。直接看confirmTransition方法中源码怎么优化的。
源码src/history/base.js文件中的confirmTransition 方法中
const abort = err => {
// changed after adding errors with
// https://github.com/vuejs/vue-router/pull/3047 before that change,
// redirect and aborted navigation would produce an err == null
if (!isNavigationFailure(err) && isError(err)) {
if (this.errorCbs.length) {
this.errorCbs.forEach(cb => {
cb(err)
})
} else {
if (process.env.NODE_ENV !== 'production') {
warn(false, 'uncaught error during route navigation:')
}
console.error(err)
}
}
onAbort && onAbort(err)
}
// 对重复,相同路由跳转时进行判断
const lastRouteIndex = route.matched.length - 1
const lastCurrentIndex = current.matched.length - 1
if (
isSameRoute(route, current) &&
// in the case the route map has been dynamically appended to
lastRouteIndex === lastCurrentIndex &&
route.matched[lastRouteIndex] === current.matched[lastCurrentIndex]
) {
this.ensureURL()
if (route.hash) {
handleScroll(this.router, current, route, false)
}
// 报错处理 createNavigationDuplicatedError方法中
return abort(createNavigationDuplicatedError(current, route))
}
而这个createNavigationDuplicatedError方法的处理错误,源码如下:
export function createNavigationDuplicatedError (from, to) {
const error = createRouterError(
from,
to,
NavigationFailureType.duplicated,
`Avoided redundant navigation to current location: "${from.fullPath}".`
)
// backwards compatible with the first introduction of Errors
error.name = 'NavigationDuplicated'
return error
}
经过这几处代码分析和阅读,可以发现,为啥会报错 overlay.js:2065 Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location: “/list”.错误了。
2.第二部分 使用prototype重写push方法 在开发如果存在报错,常规解决方案如下:
在router添加原型重新push
import Vue from 'vue'
import Router from 'vue-router'
// 重写push和报错处理
const originalPush = Router.prototype.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);
};