背景:
团队内遇到了好几次了,比如新建跳转到页面后,$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);
}
}
最后,希望能对大家有所帮助吧。如分析不对,还请大佬帮忙指出问题所在