Vue Router 常見問題
用於記錄工作遇到的Vue Router bug及常用方案
router.push報錯,Avoided redundant navigation to current location: “/xxx”
大意為 路由頻繁點擊導致路由重復,該報錯對路由跳轉功能沒有任何影響
解決方案:重寫push方法
將異常捕獲就不會報錯了
let routerPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location) {
return routerPush.call(this, location).catch(err => err)
}
重復點擊路由 刷新頁面效果
在重寫VueRouter.prototype.push方法時,利用VueRouter的currentRoute對象中的fullpath屬性與push函數的參數對比,判斷是否為同一路由。如果是,使用一下方法完成頁面刷新
方法一:window.location.reload()
問題在於會刷新整個頁面,不是很推薦
let routerPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location) {
let history = this.currentRoute && this.currentRoute.fullPath;
if (location === history) {
window.location.reload(); //整個頁面都刷新
}
return routerPush.call(this, location).catch(err => err)
}
方法二:v-if 控制router-view實現局部刷新
較為復雜,但是能夠實現局部刷新
由於VueRouter.prototype.push中的this指向VueRouter實例
該實例中存在 "全局Vue實例"(main.js new Vue()生成的) 的引用屬性 "app"(this.app)
於是,push函數里面就可以操作Vue實例了。
實現思維:
vue實例使用provide注入一個 getRouterAlive 方法,返回當前vue實例中定義的狀態變量 isRouterAlive
再定義一個 reloadChild 方法,修改狀態變量 isRouterAlive的值為false,dom更新后再改為true
需要局部刷新的地方 inject 接受 getRouterAlive 這個方法,再在router-view 上綁定
v-if="Object.prototype.toString.call(getRouterAlive) == '[object Function]' && getRouterAlive()"
實現代碼:
main.js
// main.js
new Vue({
router,
store,
render: h => h(App),
provide() {
return {
getRouterAlive: this.getRouterAlive,
}
},
data: {
isRouterAlive: true
},
methods: {
getRouterAlive() {
return this.isRouterAlive;
},
reloadChild() {
this.isRouterAlive = false;
this.$nextTick(() => {
this.isRouterAlive = true;
})
}
}
}).$mount('#app')
router.js
// router/index.js
let routerPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location) {
let history = this.currentRoute && this.currentRoute.fullPath;
if (location === history) {
this.app.reloadChild && this.app.reloadChild();
}
return routerPush.call(this, location).catch(err => err)
}
局部刷新
// 局部刷新
...
<router-view v-if="Object.prototype.toString.call(getRouterAlive) == '[object Function]' && getRouterAlive()"></router-view>
...
inject: ["getRouterAlive"],
...