编程式路由跳转到当前路由(参数不变),多次执行会抛出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方法,只不过我们进行了二次的封装
//配置路由的地方 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,()=>{},()=>{}) } }