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 | 1 | .transition-default() { |
2 | 2 | &-enter-active, |
3 | 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 | 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 | 1 | .fade-enter-active, |
2 | 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 | 6 | .fade-enter-from, |
... | ... | @@ -11,7 +11,7 @@ |
11 | 11 | // side-fade |
12 | 12 | .slide-fade-enter-active, |
13 | 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 | 17 | .slide-enter-from, |
... | ... | @@ -32,7 +32,7 @@ |
32 | 32 | // Speed: 1x |
33 | 33 | .fade-bottom-enter-active, |
34 | 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 | 38 | .fade-bottom-enter-from, |
... | ... | @@ -53,7 +53,7 @@ |
53 | 53 | // Speed: 1x |
54 | 54 | .fade-top-enter-active, |
55 | 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 | 59 | .fade-top-enter-from { | ... | ... |
src/design/transition/zoom.less
1 | 1 | // zoom-out |
2 | 2 | .zoom-out-enter-active, |
3 | 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 | 7 | .zoom-out-enter-from, |
... | ... | @@ -13,7 +13,7 @@ |
13 | 13 | // zoom-fade |
14 | 14 | .zoom-fade-enter-active, |
15 | 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 | 19 | .zoom-fade-enter-from { | ... | ... |
src/hooks/web/useTabs.ts
1 | +import { useTimeout } from '/@/hooks/core/useTimeout'; | |
2 | +import { PageEnum } from '/@/enums/pageEnum'; | |
1 | 3 | import { TabItem, tabStore } from '/@/store/modules/tab'; |
2 | 4 | import { appStore } from '/@/store/modules/app'; |
5 | +import router from '/@/router'; | |
6 | + | |
3 | 7 | type Fn = () => void; |
4 | 8 | type RouteFn = (tabItem: TabItem) => void; |
5 | 9 | |
... | ... | @@ -66,5 +70,12 @@ export function useTabs() { |
66 | 70 | closeOther: () => canIUseFn() && closeOther(tabStore.getCurrentTab), |
67 | 71 | closeCurrent: () => canIUseFn() && closeCurrent(tabStore.getCurrentTab), |
68 | 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 | 5 | import { BasicMenu } from '/@/components/Menu/index'; |
6 | 6 | import Logo from '/@/layouts/Logo.vue'; |
7 | 7 | |
8 | -import { PageEnum } from '/@/enums/pageEnum'; | |
9 | 8 | import { MenuModeEnum, MenuSplitTyeEnum, MenuTypeEnum } from '/@/enums/menuEnum'; |
10 | 9 | |
11 | 10 | // store |
... | ... | @@ -20,10 +19,11 @@ import { |
20 | 19 | getFlatChildrenMenus, |
21 | 20 | getCurrentParentPath, |
22 | 21 | } from '/@/router/menus/index'; |
23 | -import { useGo } from '/@/hooks/web/usePage'; | |
24 | 22 | import { useRouter } from 'vue-router'; |
25 | 23 | import { useThrottle } from '/@/hooks/core/useThrottle'; |
26 | 24 | import { permissionStore } from '/@/store/modules/permission'; |
25 | +import { useTabs } from '/@/hooks/web/useTabs'; | |
26 | +import { PageEnum } from '/@/enums/pageEnum'; | |
27 | 27 | |
28 | 28 | // import |
29 | 29 | export default defineComponent({ |
... | ... | @@ -54,6 +54,7 @@ export default defineComponent({ |
54 | 54 | const menusRef = ref<Menu[]>([]); |
55 | 55 | const flatMenusRef = ref<Menu[]>([]); |
56 | 56 | const { currentRoute } = useRouter(); |
57 | + const { addTab } = useTabs(); | |
57 | 58 | |
58 | 59 | const getProjectConfigRef = computed(() => { |
59 | 60 | return appStore.getProjectConfig; |
... | ... | @@ -63,7 +64,6 @@ export default defineComponent({ |
63 | 64 | return unref(getProjectConfigRef).menuSetting.mode === MenuModeEnum.HORIZONTAL; |
64 | 65 | }); |
65 | 66 | |
66 | - const go = useGo(); | |
67 | 67 | onMounted(() => { |
68 | 68 | genMenus(); |
69 | 69 | }); |
... | ... | @@ -144,7 +144,7 @@ export default defineComponent({ |
144 | 144 | if (splitType === MenuSplitTyeEnum.TOP) { |
145 | 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 | 2 | import type { TabItem } from '/@/store/modules/tab'; |
3 | 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 | 6 | import { Tabs } from 'ant-design-vue'; |
7 | 7 | import TabContent from './TabContent'; |
8 | 8 | |
... | ... | @@ -16,12 +16,21 @@ import './index.less'; |
16 | 16 | import { tabStore } from '/@/store/modules/tab'; |
17 | 17 | import { closeTab } from './useTabDropdown'; |
18 | 18 | import router from '/@/router'; |
19 | +import { useTabs } from '/@/hooks/web/useTabs'; | |
20 | +import { PageEnum } from '/@/enums/pageEnum'; | |
21 | + | |
19 | 22 | export default defineComponent({ |
20 | 23 | name: 'MultiTabs', |
21 | 24 | setup() { |
22 | 25 | let isAddAffix = false; |
23 | 26 | const go = useGo(); |
24 | 27 | const { currentRoute } = useRouter(); |
28 | + | |
29 | + onMounted(() => { | |
30 | + const { addTab } = useTabs(); | |
31 | + addTab(unref(currentRoute).path as PageEnum); | |
32 | + }); | |
33 | + | |
25 | 34 | // 当前激活tab |
26 | 35 | const activeKeyRef = ref<string>(''); |
27 | 36 | // 当前tab列表 |
... | ... | @@ -38,7 +47,9 @@ export default defineComponent({ |
38 | 47 | } |
39 | 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 | 55 | immediate: true, | ... | ... |
src/router/guard/pageLoadingGuard.ts
... | ... | @@ -6,6 +6,9 @@ import { userStore } from '/@/store/modules/user'; |
6 | 6 | export function createPageLoadingGuard(router: Router) { |
7 | 7 | let isFirstLoad = true; |
8 | 8 | router.beforeEach(async (to) => { |
9 | + console.log('======================'); | |
10 | + console.log(2); | |
11 | + console.log('======================'); | |
9 | 12 | const { |
10 | 13 | openKeepAlive, |
11 | 14 | openRouterTransition, |
... | ... | @@ -21,6 +24,7 @@ export function createPageLoadingGuard(router: Router) { |
21 | 24 | } |
22 | 25 | if (show && openKeepAlive && !isFirstLoad) { |
23 | 26 | const tabList = tabStore.getTabsState; |
27 | + | |
24 | 28 | const isOpen = tabList.some((tab) => tab.path === to.path); |
25 | 29 | appStore.setPageLoadingAction(!isOpen); |
26 | 30 | } else { | ... | ... |
src/store/modules/tab.ts
... | ... | @@ -181,6 +181,14 @@ class Tab extends VuexModule { |
181 | 181 | } |
182 | 182 | |
183 | 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 | 192 | closeRightTabAction(route: AppRouteRecordRaw | TabItem): void { |
185 | 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 | 11 | <a-button class="mr-2" @click="closeOther">关闭其他</a-button> |
12 | 12 | <a-button class="mr-2" @click="closeCurrent">关闭当前</a-button> |
13 | 13 | <a-button class="mr-2" @click="refreshPage">刷新当前</a-button> |
14 | + <a-button class="mr-2" @click="openTab">打开图标界面tab</a-button> | |
14 | 15 | </CollapseContainer> |
15 | 16 | </div> |
16 | 17 | </template> |
17 | 18 | <script lang="ts"> |
18 | 19 | import { defineComponent } from 'vue'; |
19 | 20 | import { CollapseContainer } from '/@/components/Container/index'; |
21 | + import { PageEnum } from '/@/enums/pageEnum'; | |
20 | 22 | import { useTabs } from '/@/hooks/web/useTabs'; |
21 | 23 | export default defineComponent({ |
22 | 24 | name: 'TabsDemo', |
23 | 25 | components: { CollapseContainer }, |
24 | 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 | 50 | </script> | ... | ... |