Commit f2bdf0b86dd818f3cc59fdb0c55eb1b53b222f7f
1 parent
949db963
perf: optimize multiple-tab switching effect
Showing
10 changed files
with
72 additions
and
17 deletions
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
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 './tab.data'; | @@ -2,7 +2,7 @@ import type { TabContentProps } from './tab.data'; | ||
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 './index.less'; | @@ -16,12 +16,21 @@ import './index.less'; | ||
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 '/@/store/modules/user'; | @@ -6,6 +6,9 @@ import { userStore } from '/@/store/modules/user'; | ||
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> |