瀏覽代碼

feat: tabs operation view

lrl 3 年之前
父節點
當前提交
3d34663eda

+ 5 - 1
src/plugins/element-plus/index.ts

@@ -41,6 +41,8 @@ import {
   ElTabPane,
   ElAvatar,
   ElEmpty,
+  ElCollapse,
+  ElCollapseItem,
   // 指令
   ElLoading,
   ElInfiniteScroll
@@ -106,7 +108,9 @@ const components = [
   ElTabs,
   ElTabPane,
   ElAvatar,
-  ElEmpty
+  ElEmpty,
+  ElCollapse,
+  ElCollapseItem
 ];
 // icon
 export const iconComponents = [

+ 1 - 1
src/router/index.ts

@@ -137,7 +137,7 @@ export const addAsyncRoutes = (arrRoutes: Array<RouteComponent>) => {
 // 创建路由实例
 export const router: Router = createRouter({
   history: createWebHashHistory(),
-  routes: filterTree(ascending(constantRoutes)).concat(...remainingRouter),
+  routes: ascending(constantRoutes).concat(...remainingRouter),
   scrollBehavior(to, from, savedPosition) {
     return new Promise(resolve => {
       if (savedPosition) {

+ 12 - 0
src/router/modules/tabs.ts

@@ -22,6 +22,18 @@ const tabsRouter = {
         showLink: true,
         i18n: true
       }
+    },
+    {
+      path: "/tabs/detail/:id",
+      name: "tabDetail",
+      component: () => import("/@/views/tabs/tabDetail.vue"),
+      meta: {
+        title: "",
+        showLink: false,
+        i18n: false,
+        dynamicLevel: 3,
+        realPath: "/tabs/detail"
+      }
     }
   ]
 };

+ 40 - 3
src/store/modules/multiTags.ts

@@ -4,6 +4,13 @@ import { getConfig } from "/@/config";
 import { positionType } from "./types";
 import { storageLocal } from "/@/utils/storage";
 
+interface Itag {
+  path: string;
+  parentPath: string;
+  name: string;
+  meta: any;
+}
+
 export const useMultiTagsStore = defineStore({
   id: "pure-multiTags",
   state: () => ({
@@ -34,14 +41,44 @@ export const useMultiTagsStore = defineStore({
       this.getMultiTagsCache &&
         storageLocal.setItem("responsive-tags", multiTags);
     },
-    handleTags<T>(mode: string, value?: T, position?: positionType): any {
+    handleTags<T>(
+      mode: string,
+      value?: T | Itag,
+      position?: positionType
+    ): any {
       switch (mode) {
         case "equal":
           this.multiTags = value;
           break;
         case "push":
-          this.multiTags.push(value);
-          this.tagsCache(this.multiTags);
+          {
+            const tagVal = value as Itag;
+            // 判断tag是否已存在:
+            const tagHasExits = this.multiTags.some(tag => {
+              return tag.path === tagVal?.path;
+            });
+
+            if (tagHasExits) return;
+            const meta = tagVal?.meta;
+            const dynamicLevel = meta?.dynamicLevel ?? -1;
+            if (dynamicLevel > 0) {
+              // dynamicLevel动态路由可打开的数量
+              const realPath = meta?.realPath ?? "";
+              // 获取到已经打开的动态路由数, 判断是否大于dynamicLevel
+              if (
+                this.multiTags.filter(e => e.meta?.realPath ?? "" === realPath)
+                  .length >= dynamicLevel
+              ) {
+                // 关闭第一个
+                const index = this.multiTags.findIndex(
+                  item => item.meta?.realPath === realPath
+                );
+                index !== -1 && this.multiTags.splice(index, 1);
+              }
+            }
+            this.multiTags.push(value);
+            this.tagsCache(this.multiTags);
+          }
           break;
         case "splice":
           this.multiTags.splice(position?.startIndex, position?.length);

+ 44 - 4
src/views/tabs/index.vue

@@ -1,10 +1,50 @@
-<script setup lang="ts"></script>
+<script setup lang="ts">
+import { ref } from "vue";
+import { useRouter, useRoute } from "vue-router";
+import { useMultiTagsStoreHook } from "/@/store/modules/multiTags";
+
+const router = useRouter();
+const route = useRoute();
+const activeName = ref("tag");
+
+function toDetail(index: number) {
+  useMultiTagsStoreHook().handleTags("push", {
+    path: `/tabs/detail/${index}`,
+    parentPath: route.matched[0].path,
+    name: "tabDetail",
+    meta: {
+      title: `No.${index} - 详情信息`,
+      showLink: false,
+      i18n: false,
+      dynamicLevel: 3,
+      realPath: "/tabs/detail"
+    }
+  });
+  router.push(`/tabs/detail/${index}`);
+}
+</script>
 
 <template>
-  <div class="tabs-container">111</div>
+  <el-collapse v-model="activeName" class="tabs-container">
+    <el-collapse-item
+      title="标签页复用超出限制自动关闭(使用场景: 动态路由)"
+      name="tag"
+    >
+      <el-button
+        v-for="index in 6"
+        :key="index"
+        size="medium"
+        @click="toDetail(index)"
+      >
+        打开{{ index }}详情页
+      </el-button>
+    </el-collapse-item>
+  </el-collapse>
 </template>
 
 <style lang="scss" scoped>
-// .tabs-container {
-// }
+.tabs-container {
+  padding: 10px;
+  background: #fff;
+}
 </style>

+ 11 - 0
src/views/tabs/tabDetail.vue

@@ -0,0 +1,11 @@
+<script setup lang="ts">
+import { useRoute } from "vue-router";
+const route = useRoute();
+const index = route.params?.id ?? -1;
+</script>
+
+<template>
+  <div>{{ index }} - 详情页内容在此</div>
+</template>
+
+<style lang="scss" scoped></style>