Haceral
2021-10-12 052eff91c4b63f4c9e08b80ae171e96d656ec607
perf: Improve the dynamic routing and automatically close the Tab function (#1264)

* 增加动态路由最大打开Tab数控制

* 增加动态路由打开数控制Router参数

* feat(Tab): 新增动态路由打开数限制Demo

* fix(multipleTab.ts): 将原来的打开数限制从固定的 5 修改为读取配置

Co-authored-by: Haceral <18274416193@163.com>
1个文件已添加
7个文件已修改
69 ■■■■■ 已修改文件
src/locales/lang/en/layout.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/lang/en/routes/demo.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/lang/zh-CN/layout.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/lang/zh-CN/routes/demo.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/routes/modules/demo/feat.ts 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/multipleTab.ts 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/demo/feat/tabs/TabDetail.vue 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/demo/feat/tabs/index.vue 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/lang/en/layout.ts
@@ -84,6 +84,7 @@
    breadcrumb: 'Breadcrumbs',
    breadcrumbIcon: 'Breadcrumbs Icon',
    tabs: 'Tabs',
    tabDetail: 'Tab Detail',
    tabsQuickBtn: 'Tabs quick button',
    tabsRedoBtn: 'Tabs redo button',
    tabsFoldBtn: 'Tabs flod button',
src/locales/lang/en/routes/demo.ts
@@ -67,6 +67,7 @@
    feat: 'Page Function',
    icon: 'Icon',
    tabs: 'Tabs',
    tabDetail: 'Tab Detail',
    sessionTimeout: 'Session Timeout',
    print: 'Print',
    contextMenu: 'Context Menu',
src/locales/lang/zh-CN/layout.ts
@@ -84,6 +84,7 @@
    breadcrumb: '面包屑',
    breadcrumbIcon: '面包屑图标',
    tabs: '标签页',
    tabDetail: '标签详情页',
    tabsQuickBtn: '标签页快捷按钮',
    tabsRedoBtn: '标签页刷新按钮',
    tabsFoldBtn: '标签页折叠按钮',
src/locales/lang/zh-CN/routes/demo.ts
@@ -67,6 +67,7 @@
    icon: '图标',
    sessionTimeout: '登录过期',
    tabs: '标签页操作',
    tabDetail: '标签详情页',
    print: '打印',
    contextMenu: '右键菜单',
    download: '文件下载',
src/router/routes/modules/demo/feat.ts
@@ -53,7 +53,22 @@
      component: () => import('/@/views/demo/feat/tabs/index.vue'),
      meta: {
        title: t('routes.demo.feat.tabs'),
        hideChildrenInMenu: true,
      },
      children: [
        {
          path: 'detail/:id',
          name: 'TabDetail',
          component: () => import('/@/views/demo/feat/tabs/TabDetail.vue'),
          meta: {
            currentActiveMenu: '/feat/tabs',
            title: t('routes.demo.feat.tabDetail'),
            hideMenu: true,
            dynamicLevel: 3,
            realPath: '/feat/tabs/detail',
          },
        },
      ],
    },
    {
      path: 'breadcrumb',
src/store/modules/multipleTab.ts
@@ -149,7 +149,7 @@
        this.tabList.splice(updateIndex, 1, curTab);
      } else {
        // Add tab
        // 获取动态路由层级
        // 获取动态路由打开数,超过 0 即代表需要控制打开数
        const dynamicLevel = meta?.dynamicLevel ?? -1;
        if (dynamicLevel > 0) {
          // 如果动态路由层级大于 0 了,那么就要限制该路由的打开数限制了
@@ -157,8 +157,9 @@
          // const realName: string = path.match(/(\S*)\//)![1];
          const realPath = meta?.realPath ?? '';
          // 获取到已经打开的动态路由数, 判断是否大于某一个值
          // 这里先固定为 每个动态路由最大能打开【5】个Tab
          if (this.tabList.filter((e) => e.meta?.realPath ?? '' === realPath).length >= 5) {
          if (
            this.tabList.filter((e) => e.meta?.realPath ?? '' === realPath).length >= dynamicLevel
          ) {
            // 关闭第一个
            const index = this.tabList.findIndex((item) => item.meta.realPath === realPath);
            index !== -1 && this.tabList.splice(index, 1);
src/views/demo/feat/tabs/TabDetail.vue
New file
@@ -0,0 +1,28 @@
<template>
  <PageWrapper title="Tab详情页面">
    <div>{{ index }} - 详情页内容在此</div>
  </PageWrapper>
</template>
<script lang="ts">
  import { defineComponent } from 'vue';
  import { PageWrapper } from '/@/components/Page';
  import { useTabs } from '/@/hooks/web/useTabs';
  import { useRoute } from 'vue-router';
  export default defineComponent({
    name: 'TabDetail',
    components: { PageWrapper },
    setup() {
      const route = useRoute();
      const index = route.params?.id ?? -1;
      const { setTitle } = useTabs();
      // 设置标识
      setTitle(`No.${index} - 详情信息`);
      return {
        index,
      };
    },
  });
</script>
src/views/demo/feat/tabs/index.vue
@@ -16,20 +16,28 @@
      <a-button class="mr-2" @click="closeCurrent"> 关闭当前 </a-button>
      <a-button class="mr-2" @click="refreshPage"> 刷新当前 </a-button>
    </CollapseContainer>
    <CollapseContainer class="mt-4" title="标签页复用超出限制自动关闭(使用场景: 动态路由)">
      <a-button v-for="index in 6" :key="index" class="mr-2" @click="toDetail(index)">
        打开{{ index }}详情页
      </a-button>
    </CollapseContainer>
  </PageWrapper>
</template>
<script lang="ts">
  import { defineComponent, ref } from 'vue';
  import { CollapseContainer } from '/@/components/Container/index';
  import { CollapseContainer } from '/@/components/Container';
  import { useTabs } from '/@/hooks/web/useTabs';
  import { PageWrapper } from '/@/components/Page';
  import { Input, Alert } from 'ant-design-vue';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { useGo } from '/@/hooks/web/usePage';
  export default defineComponent({
    name: 'TabsDemo',
    components: { CollapseContainer, PageWrapper, [Input.name]: Input, [Alert.name]: Alert },
    setup() {
      const go = useGo();
      const title = ref<string>('');
      const { closeAll, closeLeft, closeRight, closeOther, closeCurrent, refreshPage, setTitle } =
        useTabs();
@@ -41,12 +49,17 @@
          createMessage.error('请输入要设置的Tab标题!');
        }
      }
      function toDetail(index: number) {
        go(`/feat/tabs/detail/${index}`);
      }
      return {
        closeAll,
        closeLeft,
        closeRight,
        closeOther,
        closeCurrent,
        toDetail,
        refreshPage,
        setTabTitle,
        title,