项目需求:一个路由页面下展示多个页面,且切换时要像真正的路由一样可以携带路由参数
三个前置知识:
- vue不允许在路由栈中推入同一URL地址,否则会告警:
NavigationDuplicated: Avoided redundant navigation to current location: "/route".
- 在以
react、vue
为代表的SPA项目中,在万物皆组件的今天,所谓路由的切换其实仅是不同组件的切换而已。(写到这里,不由得想到一句话:我们从html学到了js再学到以vue/react为代表的生态框架,本质上也不过在一个div里打打闹闹而已,这个div叫#app
...)
- 路由间跳转时如果有参且参数是
query
类型时,在刷新时将不会丢失参数
基于项目需求以及前置知识:
- 画出了思维导图
- 设计基础逻辑
// page.vue
<template>
<div>
<p1 v-if="currentNode === 1"/>
<p2 v-if="currentNode === 2"/>
<p3 v-if="currentNode === 3"/>
</div>
</template>
<script>
import p1 from './p1.vue'
import p2 from './p2.vue'
import p3 from './p3.vue'
export default {
components: {
p1,
p2,
p3
},
data() {
return {
currentNode : 1 // 当前展示组件
}
}
}
</script>
一:修复重复告警问题:
为了规避前置1产生的问题,重写了routerInstance
方法
// ./router/index.js
// 重写路由push方法以规避`NavigationDuplicated: Avoided redundant navigation to current location: "/route".`告警
const originalPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch((err) => err);
};
二:设计组件切换逻辑
这里其实想了很多种方法,原先想使用
window.location.href + query
的方式,但是由于此方法会导致页面白屏而放弃,后来又尝试在每个子组件中emit
对应的值来使当前组件动态切换, 但总觉得不够优雅,遂将其作为兜底方案,直到后来想到了终极解决方案后便放弃了此方案
终极方案便是利用watch+routerQuery。
即:
index页监听routeQuery
对象,各个子组件内像使用路由跳转一样跳转(仅支持push
),而watch
存在的目的在于通过监听query的参数以进行组件间的切换。
- 浅灰标识跳转至,深灰标识回退至
贴贴:
// page.vue
watch: {
// 模拟路由跳转 -》`routerInstance`重写了router的`push`方法,因而不会告警
// 通过监听路由参数进行组件间的切换 子组件可以直接使用this.$router.push(xxx)以达到类路由跳转效果
/**
* A : 初始页: 去中间: query1 去末 query2
* B: 中间页 去末:query1 + query2 回初始不带参
* C: 末页 回中间:query2 回初始不带参
* */
"$route.query": {
handler(n) {
// 如果没有query,则展示组件1
if (!Object.values(n).length) {
this.currentNode = 1;
return;
}
// 如果有组件2必须的query1参数且query参数为1,则展示组件2
if (Object.values(n).length === 1 && `query1` in n) {
this.currentNode = 2;
return;
}
// 仅判断组件3必须参数query2,有则展示组件3
if (`query2` in n) {
this.currentNode = 3;
return;
}
// 除此以外,均展示组件1
this.currentNode = 1;
},
deep: true,
immediate: true,
},
},
在从中间页前往末页时可能并不需要query1
(中间页本身的参数),但是我们依然要加上去,这样传参的目的是为了区分末页的上一页是谁以实现back
功能(见图2)
而当我们在page页中写好了以上逻辑以后,就可以在子组件内像跳转正常路由一样跳转了,不同的是跳转的是同一个路由页,只不过参数不同,这也是我们在写这一类场景时要注意的点之一
假设page页
的路由名是/wzdxcsk
(我真的想吃烧烤),则在组件1
中想跳转组件2/组件3
则可以:
//p1.vue
// 组件1动态跳转组件2/组件3
methods:{
navToComp2(id,type){
// 动态跳转
const queryObj = {
2: {
query1: id,
},
3: {
query2: id,
},
};
this.$router.push({
path: "/wzdxcsk",
query: queryObj[type],
});
},
}
假设组件3想要回退至上一页则可以:
//p3.vue
// 组件3动态跳转组件2/组件1
methods:{
// 回退
back() {
this.$router.push({
path: "/wzdxcsk",
// 回退校验
query:
`query1` in this.$route.query
? {
query1: this.$route.query.query1,
}
: {},
});
},
}
整体逻辑:
在单页面中通过变量
currentNode
来控制子组件显隐,通过watch路由参数来控制具体哪个子组件显示,通过重写routerInstance实例的push方法来规避重复推入相同路由告警,子组件通过常规push方法实现回退&前进,前进回退时通过唯一query来判定跳转的子组件页面,由于url上有路由参数,则页面在刷新后依然可以根据watch
自动展示不同的组件 。
希望读者在遇到此类需求时可以有一个参考
以上。
标签:vue,push,跳转,组件,query,路由,页面 From: https://www.cnblogs.com/hjk1124/p/17846986.html