编程式路由跳转到当前路由(参数不变),多次执行会抛出NavigationDuplicates的警告错误机理以及解决办法

路由跳转有两种形式:声明式导航、编程式导航

声明式导航没有这类问题,因为vue-router底层已经处理好了

如果我们重复点击路由跳转的时候会遇到报错的情况

 那么,为什么编程式导航进行路由跳转的时候,就有这种警告错误呢

现在vur-router的最新版本是3.5.3

 "vue-router": "^3.5.3"

 它引入了一个promise,

我们看

 let result=this.$router.push("/search")
console.log(result)

 此时在进行路由跳转的时候可以看到控制台输出了一个promise对象

 

 那么为什么会出现这样的错误呢,

因为promise需要需要传递一个成功或者失败的回调,这样才能处理掉this的异常

此时我们可以这样解决这个问题

 let result=this.$router.push("/search",()=>{},()=>{})
            console.log(result)

 第一个回调是成功的回调

第二个是失败的回调

通过给push方法传递响应的成功或者失败的回调函数,可以捕获到当前的错误,可以解决

 但是这种方法治标不治本,将来在别的组件当中psuh|replace,编程式导航还是有类似的错误

 

我们继续往下看

this.$router.push("/search",()=>{},()=>{})
console.log(this)

  

 

 

 this就是当前的组件实例,但是他的身上有一个$router的属性

this.$router属性:当前的这个属性,属性值是vue-router类的一个实例,当在入口文件注册路由的时候,给组件实例添加的$router和$route属性

 console.log(this.$router)

 我们在看push是谁的方法 

 

 

 现在控制台输出的是vue的router类的一个实例,就是当前组件实例的一个属性,实例的身上并没有push这个方法,这个push是vue-router这个类的原型对象上的方法

VueRouter.prototype.push=function(){
    //函数的上下文为VueRouter类的一个实例
}
let $router=new VueRouter()
$router.push(***)

 如果想要治本,需要重写VueRouter原型对象上的push方法

所以我们在配置路由的文件中进行重写

我们看

import Vue from "vue"
import VueRouter from "vue-router"
//使用插件
Vue.use(VueRouter)
console.log(VueRouter)

  

 

 

 控制台输出的是一个构造函数,

我们看一下他的原型链上都有哪些方法

console.log(VueRouter.prototype)

 

 

 

 正好看到有push这个方法,所以我们此时需要重写这个方法

所以此时第一步先备份VueRouter上的push方法,因为说白了进行路由跳转的时候还是得用这个VueRouter上的push方法,只不过我们进行了二次的封装

第二步重写push和replace方法
//配置路由的地方
import Vue from "vue"
import VueRouter from "vue-router"
//使用插件
Vue.use(VueRouter)
// console.log(VueRouter.prototype)
//第一步,把VueRouter原型对象上的push方法保存一份,
//备份push方法
let originPush=VueRouter.prototype.push;
//第二步重写push和replace方法
VueRouter.prototype.push=function(){
    console.log(123)
}

 此时我们再点击跳转的时候就只能输出123了

 

 

 此时我们写的这个方法接收两个参数,第一参数是告诉原来的push方法,往哪里进行跳转,以及传递哪些参数,第二个参数是成功的回调,第三个是失败的回调

 

VueRouter.prototype.push=function(location,resolve,reject){
        console.log(this)
}

 我们可以看一下输出的上下文

 

 

 此时的上下文是VueRouter类的实例

所以此时需要进行判断

//配置路由的地方
import Vue from "vue"
import VueRouter from "vue-router"
//使用插件
Vue.use(VueRouter)
// console.log(VueRouter.prototype)
//第一步,把VueRouter原型对象上的push方法保存一份,
//备份push方法
let originPush=VueRouter.prototype.push;
//第二步重写push和replace方法
VueRouter.prototype.push=function(location,resolve,reject){
        //如果成功的回调或者失败的回调都传了
       if(resolve && reject){
           //call和apllay都可以调用函数一次,篡改函数的上下文一次,
           //但是call与apply传递参数的区别。call多个参数用逗号隔开,而apply则需要传递数组
           originPush.call(this,location,resolve,reject)
       }else{
           //成功或者失败的回调有或者没有
           originPush.call(this,location,()=>{},()=>{})
       }
}

 

所以此时的问题就解决了,此时知识重写了push方法,replace方法也一样

//配置路由的地方
import Vue from "vue"
import VueRouter from "vue-router"
//使用插件
Vue.use(VueRouter)
// console.log(VueRouter.prototype)
//第一步,把VueRouter原型对象上的push方法保存一份,
//备份push方法
let originPush=VueRouter.prototype.push;
let originReplace=VueRouter.prototype.replace;

//第二步重写push和replace方法
VueRouter.prototype.push=function(location,resolve,reject){
        //如果成功的回调或者失败的回调都传了
       if(resolve && reject){
           //call和apllay都可以调用函数一次,篡改函数的上下文一次,
           //但是call与apply传递参数的区别。call多个参数用逗号隔开,而apply则需要传递数组
           originPush.call(this,location,resolve,reject)
       }else{
           //成功或者失败的回调有或者没有
           originPush.call(this,location,()=>{},()=>{})
       }
}
VueRouter.prototype.replace=function(location,resolve,reject){
    //如果成功的回调或者失败的回调都传了
   if(resolve && reject){
       //call和apllay都可以调用函数一次,篡改函数的上下文一次,
       //但是call与apply传递参数的区别。call多个参数用逗号隔开,而apply则需要传递数组
       originReplace.call(this,location,resolve,reject)
   }else{
       //成功或者失败的回调有或者没有
       originReplace.call(this,location,()=>{},()=>{})
   }
}

  

 

posted @ 2021-09-23 22:01  keyeking  阅读(369)  评论(0编辑  收藏  举报