Commit f2bdf0b86dd818f3cc59fdb0c55eb1b53b222f7f

Authored by vben
1 parent 949db963

perf: optimize multiple-tab switching effect

src/design/transition/base.less
1 .transition-default() { 1 .transition-default() {
2 &-enter-active, 2 &-enter-active,
3 &-leave-active { 3 &-leave-active {
4 - transition: 0.3s cubic-bezier(0.25, 0.8, 0.5, 1) !important; 4 + transition: 0.2s cubic-bezier(0.25, 0.8, 0.5, 1) !important;
5 } 5 }
6 6
7 &-move { 7 &-move {
8 - transition: transform 0.6s; 8 + transition: transform 0.5s;
9 } 9 }
10 } 10 }
11 11
src/design/transition/breadcrumb.less
1 .breadcrumb-enter-active, 1 .breadcrumb-enter-active,
2 .breadcrumb-leave-active { 2 .breadcrumb-leave-active {
3 - transition: all 0.38s; 3 + transition: all 0.24s;
4 } 4 }
5 5
6 .breadcrumb-enter-from, 6 .breadcrumb-enter-from,
src/design/transition/fade.less
1 .fade-enter-active, 1 .fade-enter-active,
2 .fade-leave-active { 2 .fade-leave-active {
3 - transition: opacity 0.28s ease-in-out; 3 + transition: opacity 0.2s ease-in-out;
4 } 4 }
5 5
6 .fade-enter-from, 6 .fade-enter-from,
@@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
11 // side-fade 11 // side-fade
12 .slide-fade-enter-active, 12 .slide-fade-enter-active,
13 .slide-fade-leave-active { 13 .slide-fade-leave-active {
14 - transition: opacity 0.35s, transform 0.4s; 14 + transition: opacity 0.3s, transform 0.35s;
15 } 15 }
16 16
17 .slide-enter-from, 17 .slide-enter-from,
@@ -32,7 +32,7 @@ @@ -32,7 +32,7 @@
32 // Speed: 1x 32 // Speed: 1x
33 .fade-bottom-enter-active, 33 .fade-bottom-enter-active,
34 .fade-bottom-leave-active { 34 .fade-bottom-leave-active {
35 - transition: opacity 0.3s, transform 0.35s; 35 + transition: opacity 0.2s, transform 0.25s;
36 } 36 }
37 37
38 .fade-bottom-enter-from, 38 .fade-bottom-enter-from,
@@ -53,7 +53,7 @@ @@ -53,7 +53,7 @@
53 // Speed: 1x 53 // Speed: 1x
54 .fade-top-enter-active, 54 .fade-top-enter-active,
55 .fade-top-leave-active { 55 .fade-top-leave-active {
56 - transition: opacity 0.3s, transform 0.35s; 56 + transition: opacity 0.2s, transform 0.25s;
57 } 57 }
58 58
59 .fade-top-enter-from { 59 .fade-top-enter-from {
src/design/transition/zoom.less
1 // zoom-out 1 // zoom-out
2 .zoom-out-enter-active, 2 .zoom-out-enter-active,
3 .zoom-out-leave-active { 3 .zoom-out-leave-active {
4 - transition: opacity 0.35s ease-in-out, transform 0.45s ease-out; 4 + transition: opacity 0.2 ease-in-out, transform 0.2s ease-out;
5 } 5 }
6 6
7 .zoom-out-enter-from, 7 .zoom-out-enter-from,
@@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@
13 // zoom-fade 13 // zoom-fade
14 .zoom-fade-enter-active, 14 .zoom-fade-enter-active,
15 .zoom-fade-leave-active { 15 .zoom-fade-leave-active {
16 - transition: transform 0.35s, opacity 0.35s ease-out; 16 + transition: transform 0.2s, opacity 0.2s ease-out;
17 } 17 }
18 18
19 .zoom-fade-enter-from { 19 .zoom-fade-enter-from {
src/hooks/web/useTabs.ts
  1 +import { useTimeout } from '/@/hooks/core/useTimeout';
  2 +import { PageEnum } from '/@/enums/pageEnum';
1 import { TabItem, tabStore } from '/@/store/modules/tab'; 3 import { TabItem, tabStore } from '/@/store/modules/tab';
2 import { appStore } from '/@/store/modules/app'; 4 import { appStore } from '/@/store/modules/app';
  5 +import router from '/@/router';
  6 +
3 type Fn = () => void; 7 type Fn = () => void;
4 type RouteFn = (tabItem: TabItem) => void; 8 type RouteFn = (tabItem: TabItem) => void;
5 9
@@ -66,5 +70,12 @@ export function useTabs() { @@ -66,5 +70,12 @@ export function useTabs() {
66 closeOther: () => canIUseFn() && closeOther(tabStore.getCurrentTab), 70 closeOther: () => canIUseFn() && closeOther(tabStore.getCurrentTab),
67 closeCurrent: () => canIUseFn() && closeCurrent(tabStore.getCurrentTab), 71 closeCurrent: () => canIUseFn() && closeCurrent(tabStore.getCurrentTab),
68 resetCache: () => canIUseFn() && resetCache(), 72 resetCache: () => canIUseFn() && resetCache(),
  73 + addTab: (path: PageEnum, goTo = false) => {
  74 + useTimeout(() => {
  75 + tabStore.addTabByPathAction(path);
  76 + }, 0);
  77 +
  78 + goTo && router.push(path);
  79 + },
69 }; 80 };
70 } 81 }
src/layouts/default/LayoutMenu.tsx
@@ -5,7 +5,6 @@ import { computed, defineComponent, unref, ref, onMounted, watch } from 'vue'; @@ -5,7 +5,6 @@ import { computed, defineComponent, unref, ref, onMounted, watch } from 'vue';
5 import { BasicMenu } from '/@/components/Menu/index'; 5 import { BasicMenu } from '/@/components/Menu/index';
6 import Logo from '/@/layouts/Logo.vue'; 6 import Logo from '/@/layouts/Logo.vue';
7 7
8 -import { PageEnum } from '/@/enums/pageEnum';  
9 import { MenuModeEnum, MenuSplitTyeEnum, MenuTypeEnum } from '/@/enums/menuEnum'; 8 import { MenuModeEnum, MenuSplitTyeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
10 9
11 // store 10 // store
@@ -20,10 +19,11 @@ import { @@ -20,10 +19,11 @@ import {
20 getFlatChildrenMenus, 19 getFlatChildrenMenus,
21 getCurrentParentPath, 20 getCurrentParentPath,
22 } from '/@/router/menus/index'; 21 } from '/@/router/menus/index';
23 -import { useGo } from '/@/hooks/web/usePage';  
24 import { useRouter } from 'vue-router'; 22 import { useRouter } from 'vue-router';
25 import { useThrottle } from '/@/hooks/core/useThrottle'; 23 import { useThrottle } from '/@/hooks/core/useThrottle';
26 import { permissionStore } from '/@/store/modules/permission'; 24 import { permissionStore } from '/@/store/modules/permission';
  25 +import { useTabs } from '/@/hooks/web/useTabs';
  26 +import { PageEnum } from '/@/enums/pageEnum';
27 27
28 // import 28 // import
29 export default defineComponent({ 29 export default defineComponent({
@@ -54,6 +54,7 @@ export default defineComponent({ @@ -54,6 +54,7 @@ export default defineComponent({
54 const menusRef = ref<Menu[]>([]); 54 const menusRef = ref<Menu[]>([]);
55 const flatMenusRef = ref<Menu[]>([]); 55 const flatMenusRef = ref<Menu[]>([]);
56 const { currentRoute } = useRouter(); 56 const { currentRoute } = useRouter();
  57 + const { addTab } = useTabs();
57 58
58 const getProjectConfigRef = computed(() => { 59 const getProjectConfigRef = computed(() => {
59 return appStore.getProjectConfig; 60 return appStore.getProjectConfig;
@@ -63,7 +64,6 @@ export default defineComponent({ @@ -63,7 +64,6 @@ export default defineComponent({
63 return unref(getProjectConfigRef).menuSetting.mode === MenuModeEnum.HORIZONTAL; 64 return unref(getProjectConfigRef).menuSetting.mode === MenuModeEnum.HORIZONTAL;
64 }); 65 });
65 66
66 - const go = useGo();  
67 onMounted(() => { 67 onMounted(() => {
68 genMenus(); 68 genMenus();
69 }); 69 });
@@ -144,7 +144,7 @@ export default defineComponent({ @@ -144,7 +144,7 @@ export default defineComponent({
144 if (splitType === MenuSplitTyeEnum.TOP) { 144 if (splitType === MenuSplitTyeEnum.TOP) {
145 menuStore.commitCurrentTopSplitMenuPathState(path); 145 menuStore.commitCurrentTopSplitMenuPathState(path);
146 } 146 }
147 - go(path as PageEnum); 147 + addTab(path as PageEnum, true);
148 } 148 }
149 } 149 }
150 150
src/layouts/default/multitabs/index.tsx
@@ -2,7 +2,7 @@ import type { TabContentProps } from &#39;./tab.data&#39;; @@ -2,7 +2,7 @@ import type { TabContentProps } from &#39;./tab.data&#39;;
2 import type { TabItem } from '/@/store/modules/tab'; 2 import type { TabItem } from '/@/store/modules/tab';
3 import type { AppRouteRecordRaw } from '/@/router/types'; 3 import type { AppRouteRecordRaw } from '/@/router/types';
4 4
5 -import { defineComponent, watch, computed, ref, unref } from 'vue'; 5 +import { defineComponent, watch, computed, ref, unref, onMounted } from 'vue';
6 import { Tabs } from 'ant-design-vue'; 6 import { Tabs } from 'ant-design-vue';
7 import TabContent from './TabContent'; 7 import TabContent from './TabContent';
8 8
@@ -16,12 +16,21 @@ import &#39;./index.less&#39;; @@ -16,12 +16,21 @@ import &#39;./index.less&#39;;
16 import { tabStore } from '/@/store/modules/tab'; 16 import { tabStore } from '/@/store/modules/tab';
17 import { closeTab } from './useTabDropdown'; 17 import { closeTab } from './useTabDropdown';
18 import router from '/@/router'; 18 import router from '/@/router';
  19 +import { useTabs } from '/@/hooks/web/useTabs';
  20 +import { PageEnum } from '/@/enums/pageEnum';
  21 +
19 export default defineComponent({ 22 export default defineComponent({
20 name: 'MultiTabs', 23 name: 'MultiTabs',
21 setup() { 24 setup() {
22 let isAddAffix = false; 25 let isAddAffix = false;
23 const go = useGo(); 26 const go = useGo();
24 const { currentRoute } = useRouter(); 27 const { currentRoute } = useRouter();
  28 +
  29 + onMounted(() => {
  30 + const { addTab } = useTabs();
  31 + addTab(unref(currentRoute).path as PageEnum);
  32 + });
  33 +
25 // 当前激活tab 34 // 当前激活tab
26 const activeKeyRef = ref<string>(''); 35 const activeKeyRef = ref<string>('');
27 // 当前tab列表 36 // 当前tab列表
@@ -38,7 +47,9 @@ export default defineComponent({ @@ -38,7 +47,9 @@ export default defineComponent({
38 } 47 }
39 activeKeyRef.value = path; 48 activeKeyRef.value = path;
40 49
41 - tabStore.commitAddTab((unref(currentRoute) as unknown) as AppRouteRecordRaw); 50 + // 监听路由的话虽然可以,但是路由切换的时间会造成卡顿现象?
  51 + // 使用useTab的addTab的话,当用户手动调转,需要自行调用addTab
  52 + // tabStore.commitAddTab((unref(currentRoute) as unknown) as AppRouteRecordRaw);
42 }, 53 },
43 { 54 {
44 immediate: true, 55 immediate: true,
src/router/guard/pageLoadingGuard.ts
@@ -6,6 +6,9 @@ import { userStore } from &#39;/@/store/modules/user&#39;; @@ -6,6 +6,9 @@ import { userStore } from &#39;/@/store/modules/user&#39;;
6 export function createPageLoadingGuard(router: Router) { 6 export function createPageLoadingGuard(router: Router) {
7 let isFirstLoad = true; 7 let isFirstLoad = true;
8 router.beforeEach(async (to) => { 8 router.beforeEach(async (to) => {
  9 + console.log('======================');
  10 + console.log(2);
  11 + console.log('======================');
9 const { 12 const {
10 openKeepAlive, 13 openKeepAlive,
11 openRouterTransition, 14 openRouterTransition,
@@ -21,6 +24,7 @@ export function createPageLoadingGuard(router: Router) { @@ -21,6 +24,7 @@ export function createPageLoadingGuard(router: Router) {
21 } 24 }
22 if (show && openKeepAlive && !isFirstLoad) { 25 if (show && openKeepAlive && !isFirstLoad) {
23 const tabList = tabStore.getTabsState; 26 const tabList = tabStore.getTabsState;
  27 +
24 const isOpen = tabList.some((tab) => tab.path === to.path); 28 const isOpen = tabList.some((tab) => tab.path === to.path);
25 appStore.setPageLoadingAction(!isOpen); 29 appStore.setPageLoadingAction(!isOpen);
26 } else { 30 } else {
src/store/modules/tab.ts
@@ -181,6 +181,14 @@ class Tab extends VuexModule { @@ -181,6 +181,14 @@ class Tab extends VuexModule {
181 } 181 }
182 182
183 @Action 183 @Action
  184 + addTabByPathAction(path: string): void {
  185 + if (!path) return;
  186 + const routes = router.getRoutes();
  187 + const to = routes.find((item) => item.path === path);
  188 + to && this.commitAddTab((to as unknown) as AppRouteRecordRaw);
  189 + }
  190 +
  191 + @Action
184 closeRightTabAction(route: AppRouteRecordRaw | TabItem): void { 192 closeRightTabAction(route: AppRouteRecordRaw | TabItem): void {
185 const index = this.tabsState.findIndex((item) => item.path === route.path); 193 const index = this.tabsState.findIndex((item) => item.path === route.path);
186 194
src/views/demo/feat/tabs/index.vue
@@ -11,19 +11,40 @@ @@ -11,19 +11,40 @@
11 <a-button class="mr-2" @click="closeOther">关闭其他</a-button> 11 <a-button class="mr-2" @click="closeOther">关闭其他</a-button>
12 <a-button class="mr-2" @click="closeCurrent">关闭当前</a-button> 12 <a-button class="mr-2" @click="closeCurrent">关闭当前</a-button>
13 <a-button class="mr-2" @click="refreshPage">刷新当前</a-button> 13 <a-button class="mr-2" @click="refreshPage">刷新当前</a-button>
  14 + <a-button class="mr-2" @click="openTab">打开图标界面tab</a-button>
14 </CollapseContainer> 15 </CollapseContainer>
15 </div> 16 </div>
16 </template> 17 </template>
17 <script lang="ts"> 18 <script lang="ts">
18 import { defineComponent } from 'vue'; 19 import { defineComponent } from 'vue';
19 import { CollapseContainer } from '/@/components/Container/index'; 20 import { CollapseContainer } from '/@/components/Container/index';
  21 + import { PageEnum } from '/@/enums/pageEnum';
20 import { useTabs } from '/@/hooks/web/useTabs'; 22 import { useTabs } from '/@/hooks/web/useTabs';
21 export default defineComponent({ 23 export default defineComponent({
22 name: 'TabsDemo', 24 name: 'TabsDemo',
23 components: { CollapseContainer }, 25 components: { CollapseContainer },
24 setup() { 26 setup() {
25 - const { closeAll, closeLeft, closeRight, closeOther, closeCurrent, refreshPage } = useTabs();  
26 - return { closeAll, closeLeft, closeRight, closeOther, closeCurrent, refreshPage }; 27 + const {
  28 + closeAll,
  29 + closeLeft,
  30 + closeRight,
  31 + closeOther,
  32 + closeCurrent,
  33 + refreshPage,
  34 + addTab,
  35 + } = useTabs();
  36 +
  37 + return {
  38 + closeAll,
  39 + closeLeft,
  40 + closeRight,
  41 + closeOther,
  42 + closeCurrent,
  43 + refreshPage,
  44 + openTab: () => {
  45 + addTab('/feat/icon' as PageEnum, true);
  46 + },
  47 + };
27 }, 48 },
28 }); 49 });
29 </script> 50 </script>