vue router 需要go(-2)才能返回前一页

背景:

团队内遇到了好几次了,比如新建跳转到页面后,$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
  }
})

解决办法如下:

  1. 吧query改为path后面拼接(不建议), 如下:
this.$router.push({
  path: `/user?name=${this.name}&age=${this.age}`
})
  1. query内增加兼容处理,如下:
this.$router.push({
  path: '/user',
  query: {
    name: this.name || '',
    age: this.age || ''
  }
})

第二种方法比较正规,并且如果和我们一样对router进行封装了的话,这样的判断处理可以放到通用的地方,就像我们好多处都有这个问题,一下就解决了。

我排查的过程:

这部分是我对这个问题的原理问题分析,不对的地方,希望大佬们指出。

  1. 为什么参数丢失了

45F3B7B6D5F677973FF09BF9A2F1BEAF.jpg

vue中处理query参数的地方,这个函数作用看名字就可以看出来是将query转换为stringify,我们可以看到当value为undefined时候直接return不进行处理

  1. 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);
};
  1. 这个问题的根源

细节的原因,我懒得去跟踪了,可以确定一个大概的路。

排查的时候,我发现如果有问题,其实都会触发两次上面的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);
    }
}

最后,希望能对大家有所帮助吧。如分析不对,还请大佬帮忙指出问题所在

posted @ 2021-08-31 18:20  金振宗  阅读(882)  评论(0编辑  收藏  举报