爱是在雪地里写诗,边写边消失:父子级路由切换,组件不可见之殇
0. 缘起
我有1个el-menu生成的菜单,下面有个带着router-view的el-main,结果侧边栏的某个选项存在着点击跳转到空白页面的阴间BUG。那么,耗费在下四小时心血找到的BUG,究竟是个什么东西呢?
1. 看不见的BUG
这个BUG的表现形式还真是看不见对应组件。我有ABC三个组件,其中A作为BC的入口,点击el-menu-item里的A,再在表格之中点击不同项会跳转到对应的B页面或者C页面。
然后测试的时候,我就发现有个蜜汁BUG,点击A中的BC对应项还是A的组件,BC根本出现都没出现。我看路由已经改变,beforeEach
全局路由守卫也显示跳转到B/C对应的路由了。
不过如果设置了A的beforeEnter
路由独享的守卫,点击进入其子路由B/C,beforeEnter
是没有反应的(一开始我就掉进这个坑里面,以为路由没到呢,但其实这个beforeEnter
是这个路由独享的!例如下面就是Foo这__路由地址专用__,换了别的路由都不会触发!!!)
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
2. 过程
那么我是怎么发现这个BUG的根源在B/C上面的呢?因为我拿了个外面的D路由来作为A点击表格跳转的新路由,这个D点击就出现了,正是我需要的效果!所以我开始思索为什么作为子组件的这两个不会出现在父组件里,搜了一下,擦答案就是【使用vue-router的子路由,需要在父组件利用router-view占位。】
非常弱智的错误,我特么反应过来就知道为嘛了,因为A组件里我没有放router-view
!!!放了个测试一下,擦,B/C就能冒出来了。
不过我需要的效果是点击A表格内容,B/C取代A出现,需要出现在与A相同的router-view
窗口里!所以这两玩意应该和A是同级的!但是不应该在el-menu中出现,所以要在这里对它进行处理。
3. 代码
3.1 router.js
// Transfer Vice Page
{
path: "IEC104",
name: "IEC104",
component: () => import("@/views/demon/demonTransfer/IEC104"),
meta: {
title: "IEC104",
permissions: ["admin", "system:magicBox:list"]
},
hidden: true,
},
这里的hidden是在下一步el-menu布局中剔除无关布局项的重要flag
3.2 el-menu布局
<template>
<el-container class="zd-router-layout">
<el-aside
width="256px"
v-if="'horizontal' === layout"
:style="{ height: height }"
>
<el-menu
default-active="2"
:default-active="defaultActive"
class="el-menu-vertical-demo"
background-color="#545c64"
text-color="#fff"
router
active-text-color="#ffd04b"
>
<component
:is="
router.children && router.children.length
? 'el-submenu'
: 'el-menu-item'
"
v-for="router in routers"
:key="router.name"
:index="`/demon-box/demon-detail/${router.path}`"
>
<span
slot="title"
v-if="!router.children || !router.children.length"
>{{ router.meta.title }}</span
>
<template slot="title" v-else>{{ router.meta.title }}</template>
<component
is="el-menu-item"
v-for="child in router.children"
:key="child.name"
:index="`/demon-box/demon-detail/${router.path}/${child.path}`"
>
<span slot="title">{{ child.meta.title }}</span>
</component>
</component>
</el-menu>
</el-aside>
<el-header v-else>
<el-menu
mode="horizontal"
router
:default-active="defaultActive"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b"
>
<component
:is="
router.children && router.children.length
? 'el-submenu'
: 'el-menu-item'
"
v-for="router in routers"
:key="router.name"
:index="`/demon-box/demon-detail/${router.path}`"
>
<span
slot="title"
v-if="!router.children || !router.children.length"
>{{ router.meta.title }}</span
>
<template slot="title" v-else>{{ router.meta.title }}</template>
<component
is="el-menu-item"
v-for="child in router.children"
:key="child.name"
:index="`/demon-box/demon-detail/${router.path}/${child.path}`"
>
<span slot="title">{{ child.meta.title }}</span>
</component>
</component>
</el-menu>
</el-header>
<el-main :style="{ height: mainHeight }">
<router-view />
</el-main>
</el-container>
</template>
<script>
import { demonRoutes } from "@/router";
import { mapGetters } from "vuex";
export default {
name: "routerLayout",
data() {
return {};
},
watch: {
layout: {
handler(val) {
this.refreshRoute();
},
},
},
mounted() {
this.$baseEventBus.$on("deliverRoute", (data) => {
this.$router.push(data);
});
},
beforeDestroy() {
this.$baseEventBus.$off("deliverRoute");
},
computed: {
...mapGetters({
layout: "settings/layout",
}),
routers: {
get() {
return demonRoutes
.map((item) => {
if (item.hidden) {
return;
}
if (item.children) {
item.children = item.children.filter((ele) => !ele.hidden);
}
return item;
})
.filter((key) => key); // Filter null page (Like IEC104 & Modbus)
},
},
defaultActive: {
get() {
return this.$route.path;
},
},
height: {
get() {
return "calc(100vh - 200px)";
},
},
mainHeight: {
get() {
return "vertical" === this.layout
? "calc(100vh - 240px)"
: "calc(100vh - 180px)";
},
},
},
methods: {
async refreshRoute() {
this.$baseEventBus.$emit("reload-router-view");
this.pulse = true;
setTimeout(() => {
this.pulse = false;
}, 1000);
},
},
};
</script>
<style lang="scss" scoped>
.zd-router-layout {
.el-aside {
background-color: #545c64;
}
.el-main {
overflow: hidden;
padding: 0;
overflow-y: auto;
}
}
</style>
4. 想法
基础不牢,地动山摇。
最近有点悠闲了,看了别的内容,比如一点点GO和MONGODB,但自己这恰饭的东西,像是Vue啊JS啊ES6啊,其实还有很多不明白。需要多多练习使用。