一、原因
Vue Router
默认会认为同一路由之间的跳转是相同路由的导航,所以不会触发组件的重新渲染。
当我们连续重复跳转相同的路由导航时就会报错如:
Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location: "/homePage".
我们可以手动捕获错误:在this.$router.push
的Promise
链中添加一个.catch()
来捕获这个错误并处理它,例如给出一个警告。
this.$router.push('/homePage').catch(err => {
if (err.name !== 'NavigationDuplicated') {
throw err;
} else {
console.log('NavigationDuplicated error caught:', err);
// 在这里处理错误,例如给出警告
}
});
在实际开发中,我们经常会在路由文件中重写push
方法,使其在导航重复错误时返回错误对象。
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push (location) {
return originalPush.call(this, location).catch(err => err)
}
Vue.use(VueRouter)
当多个导航菜单用相同的路由时也会出现这种问题
二、解决方法
1、使用watch
监听route对象
在组件中使用watch
监听route
对象的变化,当路由发生变化时手动触发组件的更新
watch: {
$route(to, from) {
if (to.path === from.path) {
// 如果目标路由和来源路由的路径相同,则强制刷新页面
this.$router.go();
}
}
}
2、使用key
属性强制组件重新渲染
在需要刷新的组件中,通过设置标签的key属性为路由路径,以确保每次路由变化时都会强制重新渲染组件
<router-view :key="$route.fullPath" />
这样会导致所有路由组件
都在每次路由变化时都重新渲染,这可能不符合实际需求,尤其是对于那些不需要强制刷新的路由组件而言。在这种情况下,我们需要一种更精细化的方式来控制路由组件的刷新行为。
如:条件性地使用<router-view>的key属性
① 在路由配置中,为每个需要强制刷新的路由组件设置一个唯一的名称或者特定参数
const routes = [
{ path: '/foo', name: 'Foo', component: FooComponent },
{ path: '/bar/:id', name: 'Bar', component: BarComponent },
// 其他路由配置...
];
②在路由组件的模板中,使用路由的 name 或者特定参数的值作为 <router-view>
的 key
属性值。
<!-- 根据路由组件的名称作为 key -->
<router-view :key="$route.name" />
<!-- 或者根据某个特定参数的值作为 key -->
<router-view :key="$route.params.id" />
可以根据不同的路由组件动态地判断是否需要重新渲染,而不会影响其他不需要刷新的路由组件。
最后,使用着两种方法可以解决通过this.$router.push
跳转同一路由页面只会刷新一次的问题,但它们也存在一些缺点:
性能影响
使用watch监听$route对象或设置key属性强制组件重新渲染都会带来一定的性能开销,可能会影响页面的加载和渲染性能。潜在的副作用
强制重新渲染组件可能会导致一些意外的副作用,例如丢失用户输入的数据、重新触发组件生命周期钩子等。
页面强制刷新时,浏览器会重新加载整个页面
,包括 JavaScript、Vue 实例以及所有组件,因此会导致所有状态都被重新初始化
。比如点击导航按钮本来会根据路由匹配来给相应的菜单项添加 is-active
类,但是由于强制刷新了,这个类也被初始化了,那么导航按钮的显示没有被选中就会有问题。所以在开发中,尽量一个导航菜单对应一个路由。
暂时还没有找到好的解决办法,有其他方法的请多多指导。