1. 程式人生 > 其它 >愛是在雪地裡寫詩,邊寫邊消失:父子級路由切換,元件不可見之殤

愛是在雪地裡寫詩,邊寫邊消失:父子級路由切換,元件不可見之殤

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啊,其實還有很多不明白。需要多多練習使用。

人生到處知何似,應似飛鴻踏雪泥。