ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

探究vue-router重复路由跳转问题

2021-10-22 23:32:01  阅读:287  来源: 互联网

标签:vue return err onResolve location 跳转 push router onReject


有时候你在vue项目中做路由跳转时,可能是比如elementUI的memn同级跳转,也可能是比如root.vue中做身份校验跳转,总之,可能会遇到这样的报错:

Uncaught (in promise) NavigationDuplicated:...

你说他难看吧,也确实难看。但要说是个错误吧,也不影响正常逻辑。但是有错误还是要解决的。

这个问题其实是vue-router3版本更新后和老的写法之间的兼容问题。其实有三种解决方法。网上的解决方案几乎都是第一种,但这样是会出问题的!

先说导致问题的原因:

  1. 同一个地方(路由)触发了两次;
  2. elementUI中memn同级跳转;
  3. 笔者遇到的:在root.vue中通过watch监听路由,并做身份校验,如果不是商城版则跳转到引导页如果是但过期了就还是首页(但某些功能不能用)。这里过期的时候我们需要考虑一种情况 —— 当前在引导页然后过期了(实际当然不会只有这一种情况),这时候需要回到首页。这里报了错。

然后,怎么解决?

弄清了其原因在于“Vue-router在3.1之后把$router.push()方法改为了Promise。所以假如没有回调函数,错误信息就会交给全局的路由错误处理,因此就会报上述的错误”之后,就有三种处理方案了:

“全局”处理

网上大部分文章都是一上来就放代码:

const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location, onResolve, onReject) {
    if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
    return originalPush.call(this, location).catch(err => err)
}

,,,怎么说呢,至少我做的项目中replace的情况比push多。

其实就是重写 —— replacepush方法。笔者查阅官方文档时发现了一个API,似乎就是为了防止这种情况的发生:isNavigationFailure

所以我觉得可以在index.js/router的单独路由文件中放这样一段代码:

const originalPush = VueRouter.prototype.push
const originalReplace = VueRouter.prototype.replace

// 重写!
VueRouter.prototype.push = function push(location, onResolve, onReject) {
    // 如果指定了成功或者失败的回调
    if (onResolve || onReject) {
        return originalPush.call(this, location, onResolve, onReject)
    }
    // 没有指定成功或者失败的回调,要用catch处理
    return originalPush.call(this, location).catch((err) => {
        // 如果是重复导航产生的错误,不再向外传递错误
        if (VueRouter.isNavigationFailure(err)) {
            return err
        }

        // 如果不是重复导航的错误,将错误向下传递
        return Promise.reject(err)
    })
}

VueRouter.prototype.replace = function (location, onResolve, onReject) {
    if (onResolve || onReject) {
        return originalReplace.call(this, location, onResolve, onReject)
    }
    return originalReplace.call(this, location).catch((err) => {
        if (VueRouter.isNavigationFailure(err)) {
            return err
        }
        return Promise.reject(err)
    })
}

或者简单一点,这样写:

const originalPush = VueRouter.prototype.push;
const originalReplace = VueRouter.prototype.replace;

VueRouter.prototype.push = function push(location, onResolve, onReject) {
    if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
    return originalPush.call(this, location).catch(err => err)
}
VueRouter.prototype.replace = function push(location, onResolve, onReject) {
  if (onResolve || onReject) return originalReplace.call(this, location, onResolve, onReject)
  return originalReplace.call(this, location).catch(err => err)
}

这段代码在笔者遇到的(也就是第三种)场景下,会直接在两个页面之间一直重定向,最终导致页面卡死。

我不知道是不是因为微前端架构中多次触发的原因,因为我的组件中还有生命周期的存在。

降级

既然是因为vue-router版本更新的问题,那我们直接采用老版本不就解决问题了?

固定vue-router版本到3.0.7以下:

npm i vue-router@3.0 -S

但这不是一劳永逸的办法:随着时间的过去,这个版本一定会成为“过老的版本”,而且promise目前来看一定会被越来越多的应用。所以这个办法非常不建议使用!

回调处理(解决!)

可以看到,第一种方案在全局进行,写完以后项目的每个地方都能照顾到。但是很遗憾笔者的项目里不能用。但是vue-router的开发者给出了另一个解决方法 —— 为每一个replacepush API 增加回调函数,其原理依然是“捕获,但不暴露”:

this.$router.replace/push("xxx").catch(err => {err})

标签:vue,return,err,onResolve,location,跳转,push,router,onReject
来源: https://blog.csdn.net/qq_43624878/article/details/120915108

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有