文章目录
- 问题描述
- 路由跳转的两种形式
- 问题原因
- 解决方案
- 1. 传递回调函数
- 2. 重写 `push` 方法(推荐)
- 代码实现细节解析
- 1. 为什么不能直接使用 `this.originalPush()`?
- 2. `this` 的指向是什么?
- 3. `call(this)` 的作用
- 4. 异常捕获的意义
- 其他注意事项
- 总结
问题描述
在使用 Vue.js 的 vue-router 进行编程式路由跳转时,如果多次执行跳转到当前路由(参数不变),会抛出 NavigationDuplicated 的警告错误。这种错误通常发生在用户频繁点击按钮或执行某些操作时,导致多次触发相同的路由跳转。
路由跳转的两种形式
- 声明式导航:通过
<router-link>标签进行导航,vue-router底层已经处理好了重复导航的问题,因此不会出现此类警告。 - 编程式导航:通过
this.$router.push或this.$router.replace方法进行导航,可能会出现NavigationDuplicated警告。
问题原因
在 vue-router 3.5.3 及以上版本中,push 和 replace 方法返回一个 Promise。如果多次执行相同的路由跳转,vue-router 会检测到重复导航,并抛出 NavigationDuplicated 警告。这是为了提醒开发者避免不必要的路由跳转,从而优化应用性能。
解决方案
1. 传递回调函数
通过给 push 方法传递成功和失败的回调函数,可以捕获到当前错误,从而避免警告。
this.$router.push({name: "search",params: { keyword: this.keyword },query: { k: this.keyword.toUpperCase() }},() => {}, // 成功回调(空函数)() => {} // 失败回调(空函数)
);
缺点:
- 治标不治本,其他组件中仍需重复添加回调函数。
- 代码冗余,维护成本高。
2. 重写 push 方法(推荐)
通过全局重写 VueRouter 原型上的 push 方法,彻底解决重复导航问题。
// 保存原始的 push 方法
const originalPush = VueRouter.prototype.push;// 重写 push 方法
VueRouter.prototype.push = function push(location, onResolve, onReject) {if (onResolve || onReject) {// 若用户手动传递了回调函数,直接调用原始方法return originalPush.call(this, location, onResolve, onReject);}// 若未传递回调函数,捕获 Promise 异常return originalPush.call(this, location).catch(err => err);
};
优点:
- 一劳永逸,所有组件中均生效。
- 减少代码重复,提升可维护性。
代码实现细节解析
1. 为什么不能直接使用 this.originalPush()?
-
作用域问题:
originalPush是一个通过const定义的变量,保存了原始push方法的引用。
它并不属于VueRouter实例的成员属性,因此在重写的push方法中,this(指向 VueRouter 实例)无法直接访问originalPush。
若尝试调用this.originalPush(),会导致undefined is not a function错误。 -
正确调用方式:
必须通过originalPush.call(this, ...)显式绑定this,确保原始方法在 VueRouter 实例的上下文中执行。
2. this 的指向是什么?
- 在重写的
push方法中,this指向 调用该方法的 VueRouter 实例。
例如,当组件中调用this.$router.push()时:this.$router是VueRouter类的实例。- 因此,重写后的
push方法中的this即为该实例。
3. call(this) 的作用
-
绑定上下文:
call方法用于显式指定函数执行时的this值。
若直接调用originalPush(location),原始push方法中的this会指向全局对象(如window或undefined),导致路由操作失败。 -
类比解释:
可以理解为“借用”原始方法的能力,但明确告诉它操作发生在当前 VueRouter 实例的上下文中,类似于使用他人的工具时指定工作台。
4. 异常捕获的意义
- 通过
.catch(err => err)捕获Promise异常,避免未处理的NavigationDuplicated错误抛出。 - 这样即使重复导航,错误会被静默处理,不会影响用户体验。
其他注意事项
- 路由参数变化:若跳转时参数不同(如
keyword改变),vue-router不会视为重复导航。需确保参数传递正确。 - 性能优化:减少不必要的路由跳转,可提升应用性能和响应速度。
总结
通过重写 VueRouter 原型上的 push 方法,能够高效解决编程式导航重复跳转的警告问题。此方法不仅全局生效,还保持了代码的简洁性。
