背景:
團隊內遇到了好幾次了,比如新建跳轉到頁面后,$router.go(-2)才能返回列表頁面,並且query內寫的參數的key也沒了,所以趁着今天有時間就解決了一下,分享一下。
先說一下問題所在,方便大家先拿去測試,如果對了,那就是俺蒙對了;如果不對,那就是俺太菜了。
問題所在:
router的query為undefined(目前就發現這一種),就會導致vueRouter內部報錯,但是我沒聽說過有這種說法,所以我去跟着源碼走了一圈,發現有一個pushState,try和catch走catch了,所以走了兩遍router.push(沒去細看router哪里有捕獲這個錯誤的,只能看到這里執行兩次push)。
解決方法:
假設問題代碼如下:
// this.age = undefined
// this.name = jin
this.$router.push({
path: '/user',
query: {
name: this.name,
age: this.age
}
})
解決辦法如下:
- 吧query改為path后面拼接(不建議), 如下:
this.$router.push({
path: `/user?name=${this.name}&age=${this.age}`
})
- query內增加兼容處理,如下:
this.$router.push({
path: '/user',
query: {
name: this.name || '',
age: this.age || ''
}
})
第二種方法比較正規,並且如果和我們一樣對router進行封裝了的話,這樣的判斷處理可以放到通用的地方,就像我們好多處都有這個問題,一下就解決了。
我排查的過程:
這部分是我對這個問題的原理問題分析,不對的地方,希望大佬們指出。
- 為什么參數丟失了
vue中處理query參數的地方,這個函數作用看名字就可以看出來是將query轉換為stringify,我們可以看到當value為undefined時候直接return不進行處理
- hash方法源碼
HashHistory.prototype.push = function push(location, onComplete, onAbort) {
var this$1 = this;
var ref = this;
var fromRoute = ref.current;
this.transitionTo(location, function(route) {
pushHash(route.fullPath);
handleScroll(this$1.router, route, fromRoute, false);
onComplete && onComplete(route);
}, onAbort);
};
- 這個問題的根源
細節的原因,我懶得去跟蹤了,可以確定一個大概的路。
排查的時候,我發現如果有問題,其實都會觸發兩次上面的push方法,並且吧第二次吧undefined參數去掉了。
報錯的地方為,下面這段代碼的try/catch, 重新對導航執行了一次assign,而route可以監聽每一次location的操作,所以造成了push兩次的問題(這個我也想不明白為啥會進catch但是通過瀏覽器可以看到確實進了catch,但是e打印也是undefined)
function pushState(url, replace) {
saveScrollPosition();
// try...catch the pushState call to get around Safari
// DOM Exception 18 where it limits to 100 pushState calls
var history = window.history;
try {
if (replace) {
// preserve existing history state as it could be overriden by the user
var stateCopy = extend({}, history.state);
stateCopy.key = getStateKey();
history.replaceState(stateCopy, '', url);
} else {
history.pushState({
key: setStateKey(genStateKey())
}, '', url);
}
} catch (e) {
window.location[replace ? 'replace' : 'assign'](url);
}
}
最后,希望能對大家有所幫助吧。如分析不對,還請大佬幫忙指出問題所在