Browse Source

feat: add persistence of tabs

xiaoxian521 4 years ago
parent
commit
62ad9e6f40

+ 7 - 12
src/layout/components/sidebar/SidebarItem.vue

@@ -20,12 +20,7 @@
       </app-link>
     </template>
 
-    <el-submenu
-      v-else
-      ref="subMenu"
-      :index="resolvePath(item.path)"
-      popper-append-to-body
-    >
+    <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
       <template #title>
         <i :class="item.meta.icon"></i>
         <span>{{ $t(item.meta.title) }}</span>
@@ -53,16 +48,16 @@ export default defineComponent({
   props: {
     item: {
       type: Object as PropType<RouteRecordRaw>,
-      required: true,
+      required: true
     },
     isNest: {
       type: Boolean,
-      default: false,
+      default: false
     },
     basePath: {
       type: String,
-      default: "",
-    },
+      default: ""
+    }
   },
   setup(props) {
     const onlyOneChild = ref<RouteRecordRaw>({} as any);
@@ -71,7 +66,7 @@ export default defineComponent({
       children: RouteRecordRaw[] = [],
       parent: RouteRecordRaw
     ) {
-      const showingChildren = children.filter((item) => {
+      const showingChildren = children.filter(item => {
         if (item.hidden) {
           return false;
         } else {
@@ -96,6 +91,6 @@ export default defineComponent({
     };
 
     return { hasOneShowingChild, resolvePath, onlyOneChild };
-  },
+  }
 });
 </script>

+ 17 - 4
src/layout/components/sidebar/index.vue

@@ -22,12 +22,13 @@
 </template>
 
 <script lang="ts">
-import { computed, defineComponent } from "vue";
+import { computed, defineComponent, unref, nextTick } from "vue";
 import { useRoute, useRouter } from "vue-router";
 import { useStore } from "vuex";
 import SidebarItem from "./SidebarItem.vue";
 import { algorithm } from "../../../utils/algorithm";
 import { useDynamicRoutesHook } from "../tag/tagsHook";
+import { emitter } from "/@/utils/mitt";
 
 export default defineComponent({
   name: "sidebar",
@@ -55,15 +56,27 @@ export default defineComponent({
       if (parentPathIndex > 0) {
         parentPath = indexPath.slice(0, parentPathIndex);
       }
-      dynamicRouteTags(indexPath, parentPath);
+      // 找到当前路由的信息
+      function findCurrentRoute(routes) {
+        return routes.map((item, key) => {
+          if (item.path === indexPath) {
+            dynamicRouteTags(indexPath, parentPath, item);
+          } else {
+            if (item.children) findCurrentRoute(item.children);
+          }
+        });
+        return;
+      }
+      findCurrentRoute(algorithm.increaseIndexes(router));
+      emitter.emit("changLayoutRoute", indexPath);
     };
 
     return {
       routes: computed(() => algorithm.increaseIndexes(router)),
       activeMenu,
       isCollapse: computed(() => !store.getters.sidebar.opened),
-      menuSelect,
+      menuSelect
     };
-  },
+  }
 });
 </script>

+ 35 - 18
src/layout/components/tag/index.vue

@@ -42,11 +42,11 @@
 <script>
 import { useDynamicRoutesHook } from "./tagsHook"
 import { useRoute, useRouter } from "vue-router"
-import { ref, watchEffect, onBeforeMount, unref } from "vue"
+import { ref, watchEffect, onBeforeMount, unref, nextTick } from "vue"
 import { storageLocal } from "/@/utils/storage"
 import { emitter } from "/@/utils/mitt"
 import { toggleClass, removeClass } from "/@/utils/operate"
-import { nextTick } from 'vue'
+import { homeRoute } from "./type"
 let refreshDiv = "refresh-div"
 
 export default {
@@ -73,20 +73,25 @@ export default {
         icon: "el-icon-more",
         text: "关闭其他标签页",
         divided: true,
-        disabled: false
+        disabled: unref(routesLength) > 2 ? false : true
       },
       {
         icon: "el-icon-minus",
         text: "关闭全部标签页",
         divided: false,
-        disabled: false
+        disabled: unref(routesLength) > 1 ? false : true
       },
     ])
 
     function deleteMenu(item) {
-      let tagslen = storageLocal.getItem("routesInStorage").length - 1
-      if (tagslen === 1) {
-        tagsViews.value[1].disabled = true
+      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
       }
       deleteDynamicTag(item, route.path)
     }
@@ -115,6 +120,7 @@ export default {
 
     function onClickDrop(key, item) {
       if (item.disabled) return
+      // 当前路由信息
       switch (key) {
         case 0:
           // 重新加载
@@ -122,25 +128,22 @@ export default {
           break
         case 1:
           // 关闭当前标签页
-          deleteMenu({ meta: route.meta, path: route.path })
+          deleteMenu({ path: route.path, meta: route.meta })
           break
         case 2:
           // 关闭其他标签页
+          dRoutes.value = [homeRoute, { path: route.path, meta: route.meta }]
+          storageLocal.setItem("routesInStorage", dRoutes.value)
+          tagsViews.value[2].disabled = true
           break
         case 3:
           // 关闭全部标签页
-          dRoutes.value = [{
-            path: "/welcome",
-            meta: {
-              title: "home",
-              icon: "el-icon-s-home",
-              showLink: true,
-              savedPosition: false,
-            },
-          }]
+          dRoutes.value = [homeRoute]
           storageLocal.setItem("routesInStorage", dRoutes.value)
           router.push("/welcome")
-          tagsViews.value[1].disabled = true
+          Array.from([1, 2, 3]).forEach(v => {
+            tagsViews.value[v].disabled = true
+          })
           break
       }
     }
@@ -150,6 +153,20 @@ export default {
         if (unref(showTags) === key) return
         showTags.value = key
       })
+
+      emitter.on("changLayoutRoute", (indexPath) => {
+        let currentLen = storageLocal.getItem("routesInStorage").length
+        if (currentLen === 1) {
+          Array.from([1, 3]).forEach(v => {
+            tagsViews.value[v].disabled = false
+          })
+        }
+        if (currentLen >= 2) {
+          Array.from([1, 2, 3]).forEach(v => {
+            tagsViews.value[v].disabled = false
+          })
+        }
+      })
     })
 
     return {

+ 40 - 13
src/layout/components/tag/tagsHook.ts

@@ -1,6 +1,7 @@
-import { reactive, toRefs, nextTick, computed } from "vue";
+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[];
@@ -24,21 +25,57 @@ let dynamic: InterDynamic = reactive({
 
 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): void => {
+  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(() => {
+        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);
@@ -48,12 +85,6 @@ export function useDynamicRoutesHook() {
       }
     }
     concatPath(router.options.routes, value, parentPath);
-    // if (storageLocal.getItem("routesInStorage") && storageLocal.getItem("routesInStorage").length > 2) {
-    //   let lens = storageLocal.getItem("routesInStorage").length
-    //   let itemss = storageLocal.getItem("routesInStorage")[lens - 1]
-    //   dynamic.dRoutes.push({ path: itemss.path, meta: itemss.meta })
-    // }
-    storageLocal.setItem("routesInStorage", dynamic.dRoutes);
   };
   /**
    * @param value any 当前删除tag路由
@@ -76,16 +107,12 @@ export function useDynamicRoutesHook() {
       });
     }
   };
-  const routesLength = computed(() => {
-    return storageLocal.getItem("routesInStorage")
-      ? storageLocal.getItem("routesInStorage").length
-      : 0;
-  });
 
   return {
     ...toRefs(dynamic),
     dynamicRouteTags,
     deleteDynamicTag,
     routesLength,
+    routesStorageLists,
   };
 }

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

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