Browse Source

refactor: 标签页重构,采用响应式storage

xiaoxian521 3 years ago
parent
commit
8177de106b

+ 7 - 7
package-lock.json

@@ -27,7 +27,7 @@
         "path-to-regexp": "^6.2.0",
         "pinia": "^2.0.0-beta.2",
         "resize-observer-polyfill": "^1.5.1",
-        "responsive-storage": "^1.0.1",
+        "responsive-storage": "^1.0.4",
         "v-contextmenu": "^3.0.0",
         "vue": "^3.1.1",
         "vue-i18n": "^9.1.6",
@@ -2476,9 +2476,9 @@
       }
     },
     "node_modules/responsive-storage": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/responsive-storage/-/responsive-storage-1.0.1.tgz",
-      "integrity": "sha512-p9HXODNHkdRUgaJ+mm6qKhsQCgWo1bGHAUlvbb4II5yJnb189Hrb8kKxHfG1KlbrnAQ2wR60a2BLq1AoDLp2nA==",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/responsive-storage/-/responsive-storage-1.0.4.tgz",
+      "integrity": "sha512-egiborkG1SMM5rQYMb0J0tdnDa/yH4h4ptA/fEcMAEoSaAe9j+Z4TMHFMb8x3BrM02StNuO8sNwbwVxLj+xzcA==",
       "dependencies": {
         "vue": "^3.1.1"
       }
@@ -5067,9 +5067,9 @@
       }
     },
     "responsive-storage": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/responsive-storage/-/responsive-storage-1.0.1.tgz",
-      "integrity": "sha512-p9HXODNHkdRUgaJ+mm6qKhsQCgWo1bGHAUlvbb4II5yJnb189Hrb8kKxHfG1KlbrnAQ2wR60a2BLq1AoDLp2nA==",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/responsive-storage/-/responsive-storage-1.0.4.tgz",
+      "integrity": "sha512-egiborkG1SMM5rQYMb0J0tdnDa/yH4h4ptA/fEcMAEoSaAe9j+Z4TMHFMb8x3BrM02StNuO8sNwbwVxLj+xzcA==",
       "requires": {
         "vue": "^3.1.1"
       }

+ 2 - 2
package.json

@@ -11,7 +11,7 @@
   },
   "husky": {
     "hooks": {
-      "commit-msg": "node scripts/verify-commit.ts"
+      "commit-msg": "node scripts/verify-commit.js"
     }
   },
   "dependencies": {
@@ -35,7 +35,7 @@
     "path-to-regexp": "^6.2.0",
     "pinia": "^2.0.0-beta.2",
     "resize-observer-polyfill": "^1.5.1",
-    "responsive-storage": "^1.0.1",
+    "responsive-storage": "^1.0.4",
     "v-contextmenu": "^3.0.0",
     "vue": "^3.1.1",
     "vue-i18n": "^9.1.6",

+ 22 - 0
scripts/verify-commit.js

@@ -0,0 +1,22 @@
+const chalk = require("chalk")
+
+const msgPath = process.env.HUSKY_GIT_PARAMS
+const msg = require("fs").readFileSync(msgPath, "utf-8").trim()
+
+const commitRE = /^(revert: )?(feat|fix|polish|docs|style|refactor|perf|test|workflow|ci|chore|types)(\(.+\))?: .{1,50}/
+
+if (!commitRE.test(msg)) {
+  console.error(
+    `  ${chalk.bgRed.white(" ERROR ")} ${chalk.red(
+      "不合法的 commit 消息格式"
+    )}\n\n` +
+    chalk.red("  请使用正确的提交格式:\n\n") +
+    `    ${chalk.green("feat: add 'comments' option")}\n` +
+    `    ${chalk.green("fix: handle events on blur (close #28)")}\n\n` +
+    chalk.red(
+      "  请查看 git commit 提交规范:https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md \n"
+    )
+  )
+
+  process.exit(1)
+}

+ 0 - 23
scripts/verify-commit.ts

@@ -1,23 +0,0 @@
-const chalk = require("chalk");
-
-const msgPath = process.env.HUSKY_GIT_PARAMS;
-const msg = require("fs").readFileSync(msgPath, "utf-8").trim();
-
-const commitRE = /^(revert: )?(feat|fix|polish|docs|style|refactor|perf|test|workflow|ci|chore|types)(\(.+\))?: .{1,50}/;
-
-if (!commitRE.test(msg)) {
-  console.log();
-  console.error(
-    `  ${chalk.bgRed.white(" ERROR ")} ${chalk.red(
-      "不合法的 commit 消息格式"
-    )}\n\n` +
-      chalk.red("  请使用正确的提交格式:\n\n") +
-      `    ${chalk.green("feat: add 'comments' option")}\n` +
-      `    ${chalk.green("fix: handle events on blur (close #28)")}\n\n` +
-      chalk.red(
-        "  请查看 git commit 提交规范:https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md \n"
-      )
-  );
-
-  process.exit(1);
-}

+ 5 - 5
src/layout/components/sidebar/index.vue

@@ -34,7 +34,6 @@ import { useRoute, useRouter } from "vue-router";
 import { useAppStoreHook } from "/@/store/modules/app";
 import SidebarItem from "./SidebarItem.vue";
 import { algorithm } from "../../../utils/algorithm";
-import { useDynamicRoutesHook } from "../tag/tagsHook";
 import { emitter } from "/@/utils/mitt";
 import Logo from "./Logo.vue";
 import { storageLocal } from "/@/utils/storage";
@@ -62,8 +61,6 @@ export default defineComponent({
       return path;
     });
 
-    const { dynamicRouteTags } = useDynamicRoutesHook();
-
     const menuSelect = (indexPath: string): void => {
       let parentPath = "";
       let parentPathIndex = indexPath.lastIndexOf("/");
@@ -74,7 +71,11 @@ export default defineComponent({
       function findCurrentRoute(routes) {
         return routes.map((item, key) => {
           if (item.path === indexPath) {
-            dynamicRouteTags(indexPath, parentPath, item);
+            // 切换左侧菜单 通知标签页
+            emitter.emit("changLayoutRoute", {
+              indexPath,
+              parentPath
+            });
           } else {
             if (item.children) findCurrentRoute(item.children);
           }
@@ -82,7 +83,6 @@ export default defineComponent({
         return;
       }
       findCurrentRoute(algorithm.increaseIndexes(router));
-      emitter.emit("changLayoutRoute", indexPath);
     };
 
     onBeforeMount(() => {

+ 137 - 57
src/layout/components/tag/index.vue

@@ -72,8 +72,6 @@
 </template>
 
 <script lang='ts'>
-import { useDynamicRoutesHook } from "./tagsHook";
-import { useRoute, useRouter } from "vue-router";
 import {
   ref,
   watchEffect,
@@ -83,22 +81,39 @@ import {
   nextTick,
   getCurrentInstance
 } from "vue";
+import { useRoute, useRouter } from "vue-router";
 import { storageLocal } from "/@/utils/storage";
 import { emitter } from "/@/utils/mitt";
 import { toggleClass, removeClass, hasClass } from "/@/utils/operate";
 import { templateRef } from "@vueuse/core";
-import { homeRoute } from "./type";
 let refreshButton = "refresh-button";
 
+let routerArrays = [
+  {
+    path: "/welcome",
+    meta: {
+      title: "message.hshome",
+      icon: "el-icon-s-home",
+      showLink: true,
+      savedPosition: false
+    }
+  }
+];
 export default {
+  computed: {
+    dynamicTagList() {
+      if (
+        !this.$storage.routesInStorage ||
+        this.$storage.routesInStorage.length === 0
+      ) {
+        this.$storage.routesInStorage = routerArrays;
+      }
+      return this.$storage.routesInStorage;
+    }
+  },
   setup() {
     let vm: any;
-    const {
-      deleteDynamicTag,
-      dynamicRouteTags,
-      dRoutes,
-      routesLength
-    } = useDynamicRoutesHook();
+    let st: any;
     const route = useRoute();
     const router = useRouter();
     const showTags = ref(storageLocal.getItem("tagsVal") || false);
@@ -116,21 +131,21 @@ export default {
         icon: "el-icon-close",
         text: "关闭当前标签页",
         divided: false,
-        disabled: unref(routesLength) > 1 ? false : true,
+        disabled: routerArrays.length > 1 ? false : true,
         show: true
       },
       {
         icon: "el-icon-more",
         text: "关闭其他标签页",
         divided: true,
-        disabled: unref(routesLength) > 2 ? false : true,
+        disabled: routerArrays.length > 2 ? false : true,
         show: true
       },
       {
         icon: "el-icon-minus",
         text: "关闭全部标签页",
         divided: false,
-        disabled: unref(routesLength) > 1 ? false : true,
+        disabled: routerArrays.length > 1 ? false : true,
         show: true
       }
     ]);
@@ -148,30 +163,33 @@ export default {
     // 当前右键选中的路由信息
     let currentSelect = ref({});
 
-    function deleteMenu(item) {
-      let tagslen = storageLocal.getItem("routesInStorage").length;
-      if (tagslen === 2) {
-        Array.from([1, 2, 3]).forEach(v => {
-          tagsViews.value[v].disabled = true;
-        });
-      }
-      if (tagslen === 3) {
-        tagsViews.value[2].disabled = true;
+    function dynamicRouteTag(value: string, parentPath: string): void {
+      const hasValue = st.routesInStorage.some((item: any) => {
+        return item.path === value;
+      });
+
+      function concatPath(arr: object[], value: string, parentPath: string) {
+        if (!hasValue) {
+          arr.forEach((arrItem: any) => {
+            let pathConcat = parentPath + arrItem.path;
+            if (arrItem.path === value || pathConcat === value) {
+              routerArrays.push({
+                path: value,
+                meta: arrItem.meta
+              });
+              st.routesInStorage = routerArrays;
+            } else {
+              if (arrItem.children && arrItem.children.length > 0) {
+                concatPath(arrItem.children, value, parentPath);
+              }
+            }
+          });
+        }
       }
-      deleteDynamicTag(item, route.path);
+      concatPath(router.options.routes, value, parentPath);
     }
 
-    // 初始化页面刷新保证当前路由tabview存在
-    let stop = watchEffect(() => {
-      let parentPath = route.path.slice(0, route.path.lastIndexOf("/"));
-      dynamicRouteTags(route.path, parentPath, route);
-    });
-
-    setTimeout(() => {
-      // 监听只执行一次,但获取不到当前路由,需要下一个事件轮询中取消监听
-      stop();
-    });
-
+    // 重新加载
     function onFresh() {
       toggleClass(true, refreshButton, document.querySelector(".rotate"));
       const { path, fullPath } = unref(route);
@@ -183,6 +201,57 @@ export default {
       }, 600);
     }
 
+    function deleteDynamicTag(obj: any, current: any, other: any) {
+      let valueIndex: number = routerArrays.findIndex((item: any) => {
+        return item.path === obj.path;
+      });
+
+      if (other) {
+        st.routesInStorage = routerArrays = [
+          {
+            path: "/welcome",
+            meta: {
+              title: "message.hshome",
+              icon: "el-icon-s-home",
+              showLink: true,
+              savedPosition: false
+            }
+          },
+          obj
+        ];
+        router.push(obj.path);
+        Array.from([2]).forEach(v => {
+          tagsViews.value[v].disabled = true;
+        });
+      } else {
+        // 从当前匹配到的路径中删除
+        routerArrays.splice(valueIndex, 1);
+        st.routesInStorage = routerArrays;
+      }
+
+      if (current === obj.path) {
+        // 如果删除当前激活tag就自动切换到最后一个tag
+        let newRoute: any = routerArrays.slice(-1);
+        nextTick(() => {
+          router.push({
+            path: newRoute[0].path
+          });
+        });
+      }
+    }
+
+    function deleteMenu(item, other = false) {
+      if (routerArrays.length === 2) {
+        Array.from([1, 2, 3]).forEach(v => {
+          tagsViews.value[v].disabled = true;
+        });
+      }
+      if (routerArrays.length === 3) {
+        tagsViews.value[2].disabled = true;
+      }
+      deleteDynamicTag(item, route.path, other);
+    }
+
     function onClickDrop(key, item, selectRoute) {
       if (item && item.disabled) return;
       // 当前路由信息
@@ -199,17 +268,20 @@ export default {
           break;
         case 2:
           // 关闭其他标签页
-          dRoutes.value = selectRoute
-            ? [homeRoute, { path: selectRoute.path, meta: selectRoute.meta }]
-            : [homeRoute, { path: route.path, meta: route.meta }];
-          storageLocal.setItem("routesInStorage", dRoutes.value);
-          tagsViews.value[2].disabled = true;
-          if (selectRoute) router.push(selectRoute.path);
+          selectRoute
+            ? deleteMenu(
+                {
+                  path: selectRoute.path,
+                  meta: selectRoute.meta
+                },
+                true
+              )
+            : deleteMenu({ path: route.path, meta: route.meta }, true);
           break;
         case 3:
           // 关闭全部标签页
-          dRoutes.value = [homeRoute];
-          storageLocal.setItem("routesInStorage", dRoutes.value);
+          routerArrays.splice(1, routerArrays.length);
+          st.routesInStorage = routerArrays;
           router.push("/welcome");
           Array.from([1, 2, 3]).forEach(v => {
             tagsViews.value[v].disabled = true;
@@ -235,6 +307,12 @@ export default {
         Array.from([1, 2, 3]).forEach(v => {
           tagsViews.value[v].show = true;
         });
+      } else if (st.routesInStorage.length === 2) {
+        // 只有两个标签时不显示关闭其他标签页
+        tagsViews.value[2].show = false;
+        Array.from([0, 1, 3]).forEach(v => {
+          tagsViews.value[v].show = true;
+        });
       } else {
         Array.from([0, 1, 2, 3]).forEach(v => {
           tagsViews.value[v].show = true;
@@ -260,17 +338,6 @@ export default {
       visible.value = false;
     }
 
-    watch(
-      () => visible.value,
-      val => {
-        if (val) {
-          document.body.addEventListener("click", closeMenu);
-        } else {
-          document.body.removeEventListener("click", closeMenu);
-        }
-      }
-    );
-
     // 鼠标移入
     function onMouseenter(item, index) {
       if (index) activeIndex.value = index;
@@ -299,8 +366,20 @@ export default {
       }
     }
 
+    watch(
+      () => visible.value,
+      val => {
+        if (val) {
+          document.body.addEventListener("click", closeMenu);
+        } else {
+          document.body.removeEventListener("click", closeMenu);
+        }
+      }
+    );
+
     onBeforeMount(() => {
       vm = getCurrentInstance();
+      st = vm.appContext.app.config.globalProperties.$storage;
 
       emitter.on("tagViewsChange", key => {
         if (unref(showTags) === key) return;
@@ -311,14 +390,16 @@ export default {
         showModel.value = key;
       });
 
-      emitter.on("changLayoutRoute", indexPath => {
-        let currentLen = storageLocal.getItem("routesInStorage").length;
-        if (currentLen === 1) {
+      //  接收侧边栏切换传递过来的参数
+      emitter.on("changLayoutRoute", ({ indexPath, parentPath }) => {
+        dynamicRouteTag(indexPath, parentPath);
+
+        if (routerArrays.length === 2) {
           Array.from([1, 3]).forEach(v => {
             tagsViews.value[v].disabled = false;
           });
         }
-        if (currentLen >= 2) {
+        if (routerArrays.length > 2) {
           Array.from([1, 2, 3]).forEach(v => {
             tagsViews.value[v].disabled = false;
           });
@@ -327,7 +408,6 @@ export default {
     });
 
     return {
-      dynamicTagList: useDynamicRoutesHook().dRoutes,
       deleteMenu,
       showTags,
       onFresh,

+ 0 - 120
src/layout/components/tag/tagsHook.ts

@@ -1,120 +0,0 @@
-import { reactive, toRefs, unref, nextTick, computed } from "vue";
-import { storageLocal } from "/@/utils/storage";
-import { useRouter } from "vue-router";
-import { homeRoute } from "./type";
-
-interface InterDynamic {
-  dRoutes: object[];
-  [propName: string]: any;
-}
-
-// 默认显示首页tag
-let dynamic: InterDynamic = reactive({
-  dRoutes: [
-    {
-      path: "/welcome",
-      meta: {
-        title: "message.hshome",
-        icon: "el-icon-s-home",
-        showLink: true,
-        savedPosition: false,
-      },
-    },
-  ],
-});
-
-export function useDynamicRoutesHook() {
-  const router = useRouter();
-  const routesLength = computed(() => {
-    return storageLocal.getItem("routesInStorage")
-      ? storageLocal.getItem("routesInStorage").length
-      : 0;
-  });
-  // 返回当前路由组成的数组
-  const routesStorageLists = computed(() => {
-    return storageLocal.getItem("routesInStorage")
-      ? storageLocal.getItem("routesInStorage")
-      : [];
-  });
-  /**
-   * @param value string 当前menu对应的路由path
-   * @param parentPath string 当前路由中父级路由
-   */
-  const dynamicRouteTags = (
-    value: string,
-    parentPath: string,
-    route: any
-  ): void => {
-    nextTick(() => {
-      if (unref(routesStorageLists).length > 2) {
-        dynamic.dRoutes = unref(routesStorageLists);
-        return;
-      }
-    });
-
-    const hasValue = dynamic.dRoutes.some((item: any) => {
-      return item.path === value;
-    });
-
-    if (route) {
-      let ramStorage = storageLocal.getItem("routesInStorage");
-      nextTick(() => {
-        if (ramStorage) {
-          let currentIndex = ramStorage.findIndex((v) => v.path === route.path);
-          if (currentIndex !== -1) return;
-          ramStorage.push({ path: route.path, meta: route.meta });
-          storageLocal.setItem("routesInStorage", ramStorage);
-        }
-      });
-    }
-
-    function concatPath(arr: object[], value: string, parentPath: string) {
-      if (!hasValue) {
-        arr.forEach((arrItem: any) => {
-          let pathConcat = parentPath + "/" + arrItem.path;
-          if (arrItem.path === value || pathConcat === value) {
-            dynamic.dRoutes.push({ path: value, meta: arrItem.meta });
-
-            unref(routesLength) === 0
-              ? storageLocal.setItem("routesInStorage", dynamic.dRoutes)
-              : [];
-          } else {
-            if (arrItem.children && arrItem.children.length > 0) {
-              concatPath(arrItem.children, value, parentPath);
-            }
-          }
-        });
-      }
-    }
-    concatPath(router.options.routes, value, parentPath);
-  };
-  /**
-   * @param value any 当前删除tag路由
-   * @param current objct 当前激活路由对象
-   */
-  const deleteDynamicTag = async (obj: any, current: any): Promise<any> => {
-    let valueIndex: number = dynamic.dRoutes.findIndex((item: any) => {
-      return item.path === obj.path;
-    });
-    // 从当前匹配到的路径中删除
-    await dynamic.dRoutes.splice(valueIndex, 1);
-    storageLocal.setItem("routesInStorage", dynamic.dRoutes);
-    if (current === obj.path) {
-      // 如果删除当前激活tag就自动切换到最后一个tag
-      let newRoute: any = dynamic.dRoutes.slice(-1);
-      nextTick(() => {
-        router.push({
-          path: newRoute[0].path,
-        });
-      });
-    }
-  };
-
-  return {
-    ...toRefs(dynamic),
-    dynamicRouteTags,
-    deleteDynamicTag,
-    routesLength,
-    routesStorageLists,
-  };
-}

+ 0 - 15
src/layout/components/tag/type.ts

@@ -1,15 +0,0 @@
-interface RouteModel {
-  readonly path: string;
-  readonly meta: object;
-}
-
-// 固定首页路由
-export const homeRoute: RouteModel = {
-  path: "/welcome",
-  meta: {
-    title: "message.hshome",
-    icon: "el-icon-s-home",
-    showLink: true,
-    savedPosition: false,
-  },
-};

+ 1 - 0
src/main.ts

@@ -26,6 +26,7 @@ app.config.globalProperties.$config = getConfig();
 import Storage from "responsive-storage";
 
 app.use(Storage, {
+  // 默认显示首页tag
   routesInStorage: {
     type: String,
     default: Storage.getData(undefined, "routesInStorage") ?? [

+ 7 - 7
src/router/modules/nested.ts

@@ -14,7 +14,7 @@ const nestedRouter = {
   },
   children: [
     {
-      path: "menu1",
+      path: "/nested/menu1",
       component: () => import("/@/views/nested/menu1/index.vue"),
       name: "Menu1",
       meta: {
@@ -25,7 +25,7 @@ const nestedRouter = {
       redirect: "/nested/menu1/menu1-1",
       children: [
         {
-          path: "menu1-1",
+          path: "/nested/menu1/menu1-1",
           component: () => import("/@/views/nested/menu1/menu1-1/index.vue"),
           name: "Menu1-1",
           meta: {
@@ -35,7 +35,7 @@ const nestedRouter = {
           },
         },
         {
-          path: "menu1-2",
+          path: "/nested/menu1/menu1-2",
           component: () => import("/@/views/nested/menu1/menu1-2/index.vue"),
           name: "Menu1-2",
           redirect: "/nested/menu1/menu1-2/menu1-2-1",
@@ -46,7 +46,7 @@ const nestedRouter = {
           },
           children: [
             {
-              path: "menu1-2-1",
+              path: "/nested/menu1/menu1-2/menu1-2-1",
               component: () =>
                 import("/@/views/nested/menu1/menu1-2/menu1-2-1/index.vue"),
               name: "Menu1-2-1",
@@ -57,7 +57,7 @@ const nestedRouter = {
               },
             },
             {
-              path: "menu1-2-2",
+              path: "/nested/menu1/menu1-2/menu1-2-2",
               component: () =>
                 import("/@/views/nested/menu1/menu1-2/menu1-2-2/index.vue"),
               name: "Menu1-2-2",
@@ -70,7 +70,7 @@ const nestedRouter = {
           ],
         },
         {
-          path: "menu1-3",
+          path: "/nested/menu1/menu1-3",
           component: () => import("/@/views/nested/menu1/menu1-3/index.vue"),
           name: "Menu1-3",
           meta: {
@@ -82,7 +82,7 @@ const nestedRouter = {
       ],
     },
     {
-      path: "menu2",
+      path: "/nested/menu2",
       name: "Menu2",
       component: () => import("/@/views/nested/menu2/index.vue"),
       meta: {