爱是在雪地里写诗,边写边消失:父子级路由切换,组件不可见之殇

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) => {
        // ...
      }
    }
  ]
})

导航守卫 | Vue Router (vuejs.org)

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啊,其实还有很多不明白。需要多多练习使用。

posted @ 2022-01-10 10:47  乐盘游  阅读(109)  评论(0编辑  收藏  举报