From f4621cc66411d8ff4ca852b548a79cd3da9be1ce Mon Sep 17 00:00:00 2001 From: vben Date: Fri, 4 Dec 2020 21:25:33 +0800 Subject: [PATCH] perf: perf loading logic --- CHANGELOG.zh_CN.md | 4 + src/components/Loading/src/index.vue | 2 +- src/hooks/setting/useMultipleTabSetting.ts | 3 - src/hooks/setting/useTransitionSetting.ts | 4 +- src/hooks/web/usePage.ts | 5 +- src/layouts/default/content/index.less | 5 +- src/layouts/default/content/index.tsx | 9 ++- src/layouts/default/setting/SettingDrawer.tsx | 1 - src/layouts/page/ParentView.vue | 45 ++++++++++++ src/layouts/page/index.tsx | 72 ++++++++++++++++++ src/layouts/page/index.vue | 21 ------ src/layouts/{parent => page}/useCache.ts | 6 +- src/layouts/parent/index.vue | 73 ------------------- src/layouts/parent/useTransition.ts | 22 ------ src/router/constant.ts | 7 +- src/router/guard/index.ts | 19 +++-- src/router/guard/pageLoadingGuard.ts | 34 ++------- src/router/guard/progressGuard.ts | 6 +- src/router/helper/routeHelper.ts | 16 ---- src/router/index.ts | 4 + src/router/types.d.ts | 2 - src/settings/projectSetting.ts | 2 - src/store/modules/app.ts | 2 +- src/store/modules/user.ts | 8 +- src/types/config.d.ts | 2 - src/views/sys/redirect/index.vue | 11 +-- 26 files changed, 167 insertions(+), 218 deletions(-) create mode 100644 src/layouts/page/ParentView.vue create mode 100644 src/layouts/page/index.tsx delete mode 100644 src/layouts/page/index.vue rename src/layouts/{parent => page}/useCache.ts (94%) delete mode 100644 src/layouts/parent/index.vue delete mode 100644 src/layouts/parent/useTransition.ts diff --git a/CHANGELOG.zh_CN.md b/CHANGELOG.zh_CN.md index e7f63781..71279d66 100644 --- a/CHANGELOG.zh_CN.md +++ b/CHANGELOG.zh_CN.md @@ -11,6 +11,10 @@ - i18n 支持 vscode `i18n-ally`插件 - 新增多级路由缓存示例 +### ⚡ Performance Improvements + +- 页面切换 loading 逻辑修改。对于已经加载过的页面不管有没有关闭,再次打开不会在显示 loading(已经打开过的页面在此打开速度比较快),刷新后恢复。 + ### 🎫 Chores - 首屏 loading 修改 diff --git a/src/components/Loading/src/index.vue b/src/components/Loading/src/index.vue index 4d24a734..edd32b0d 100644 --- a/src/components/Loading/src/index.vue +++ b/src/components/Loading/src/index.vue @@ -76,7 +76,7 @@ position: absolute; top: 0; left: 0; - z-index: 1; + z-index: 300; } } diff --git a/src/hooks/setting/useMultipleTabSetting.ts b/src/hooks/setting/useMultipleTabSetting.ts index 5f7c6bba..9ba8c719 100644 --- a/src/hooks/setting/useMultipleTabSetting.ts +++ b/src/hooks/setting/useMultipleTabSetting.ts @@ -7,8 +7,6 @@ import { appStore } from '/@/store/modules/app'; export function useMultipleTabSetting() { const getMultipleTabSetting = computed(() => appStore.getProjectConfig.multiTabsSetting); - const getMax = computed(() => unref(getMultipleTabSetting).max); - const getShowMultipleTab = computed(() => unref(getMultipleTabSetting).show); const getShowQuick = computed(() => unref(getMultipleTabSetting).showQuick); @@ -21,7 +19,6 @@ export function useMultipleTabSetting() { setMultipleTabSetting, getMultipleTabSetting, - getMax, getShowMultipleTab, getShowQuick, }; diff --git a/src/hooks/setting/useTransitionSetting.ts b/src/hooks/setting/useTransitionSetting.ts index ce7f759e..bbc24185 100644 --- a/src/hooks/setting/useTransitionSetting.ts +++ b/src/hooks/setting/useTransitionSetting.ts @@ -11,8 +11,8 @@ export function useTransitionSetting() { const getOpenNProgress = computed(() => unref(getTransitionSetting)?.openNProgress); - const getOpenPageLoading = computed(() => { - return unref(getTransitionSetting)?.openPageLoading && unref(getEnableTransition); + const getOpenPageLoading = computed((): boolean => { + return !!unref(getTransitionSetting)?.openPageLoading; }); const getBasicTransition = computed(() => unref(getTransitionSetting)?.basicTransition); diff --git a/src/hooks/web/usePage.ts b/src/hooks/web/usePage.ts index 1b3df117..bcf4483b 100644 --- a/src/hooks/web/usePage.ts +++ b/src/hooks/web/usePage.ts @@ -11,10 +11,7 @@ export type RouteLocationRawEx = Omit & { path: PageEn function handleError(e: Error) { console.error(e); - // 101是为了 大于 打开时候设置的100延时防止闪动 - setTimeout(() => { - appStore.commitPageLoadingState(false); - }, 101); + appStore.commitPageLoadingState(false); } // page switch diff --git a/src/layouts/default/content/index.less b/src/layouts/default/content/index.less index 6912f98d..7141f73c 100644 --- a/src/layouts/default/content/index.less +++ b/src/layouts/default/content/index.less @@ -12,10 +12,7 @@ &__loading { position: absolute; + top: 200px; z-index: @page-loading-z-index; - - > .basic-loading { - margin-bottom: 15%; - } } } diff --git a/src/layouts/default/content/index.tsx b/src/layouts/default/content/index.tsx index 8e69d0a0..d4ca3c57 100644 --- a/src/layouts/default/content/index.tsx +++ b/src/layouts/default/content/index.tsx @@ -5,7 +5,7 @@ import { Loading } from '/@/components/Loading'; import { useRootSetting } from '/@/hooks/setting/useRootSetting'; import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting'; -import PageLayout from '/@/layouts/page/index.vue'; +import PageLayout from '/@/layouts/page/index'; export default defineComponent({ name: 'LayoutContent', setup() { @@ -16,7 +16,12 @@ export default defineComponent({ return (
{unref(getOpenPageLoading) && ( - + )}
diff --git a/src/layouts/default/setting/SettingDrawer.tsx b/src/layouts/default/setting/SettingDrawer.tsx index 7f03d456..81b48bdd 100644 --- a/src/layouts/default/setting/SettingDrawer.tsx +++ b/src/layouts/default/setting/SettingDrawer.tsx @@ -465,7 +465,6 @@ export default defineComponent({ baseHandler(HandlerEnum.OPEN_PAGE_LOADING, e); }, def: unref(getOpenPageLoading), - disabled: !unref(getEnableTransition), })} {renderSwitchItem(t('layout.setting.switchAnimation'), { diff --git a/src/layouts/page/ParentView.vue b/src/layouts/page/ParentView.vue new file mode 100644 index 00000000..46738f13 --- /dev/null +++ b/src/layouts/page/ParentView.vue @@ -0,0 +1,45 @@ + + + diff --git a/src/layouts/page/index.tsx b/src/layouts/page/index.tsx new file mode 100644 index 00000000..e0d6bf19 --- /dev/null +++ b/src/layouts/page/index.tsx @@ -0,0 +1,72 @@ +import type { FunctionalComponent } from 'vue'; + +import { computed, defineComponent, unref, Transition, KeepAlive } from 'vue'; +import { RouterView, RouteLocation } from 'vue-router'; + +import FrameLayout from '/@/layouts/iframe/index.vue'; + +import { useRootSetting } from '/@/hooks/setting/useRootSetting'; + +import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting'; +import { useCache } from './useCache'; +import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting'; + +interface DefaultContext { + Component: FunctionalComponent; + route: RouteLocation; +} + +export default defineComponent({ + name: 'PageLayout', + setup() { + const { getCaches } = useCache(true); + const { getShowMultipleTab } = useMultipleTabSetting(); + + const { getOpenKeepAlive, getCanEmbedIFramePage } = useRootSetting(); + + const { getBasicTransition, getEnableTransition } = useTransitionSetting(); + + const openCache = computed(() => unref(getOpenKeepAlive) && unref(getShowMultipleTab)); + + return () => { + return ( + <> + + {{ + default: ({ Component, route }: DefaultContext) => { + // No longer show animations that are already in the tab + const cacheTabs = unref(getCaches); + const isInCache = cacheTabs.includes(route.name as string); + const name = + isInCache && route.meta.loaded && unref(getEnableTransition) + ? 'fade-slide' + : null; + + const renderComp = () => ; + + const PageContent = unref(openCache) ? ( + {renderComp()} + ) : ( + renderComp() + ); + + return unref(getEnableTransition) ? ( + + {() => PageContent} + + ) : ( + PageContent + ); + }, + }} + + {unref(getCanEmbedIFramePage) && } + + ); + }; + }, +}); diff --git a/src/layouts/page/index.vue b/src/layouts/page/index.vue deleted file mode 100644 index d197b021..00000000 --- a/src/layouts/page/index.vue +++ /dev/null @@ -1,21 +0,0 @@ - - diff --git a/src/layouts/parent/useCache.ts b/src/layouts/page/useCache.ts similarity index 94% rename from src/layouts/parent/useCache.ts rename to src/layouts/page/useCache.ts index d02df4b8..959362d7 100644 --- a/src/layouts/parent/useCache.ts +++ b/src/layouts/page/useCache.ts @@ -10,9 +10,8 @@ export function useCache(isPage: boolean) { const name = ref(''); const { currentRoute } = useRouter(); - tryTsxEmit((instance: any) => { - const routeName = instance.ctx.$options.name; - + tryTsxEmit((instance) => { + const routeName = instance.type.name; if (routeName && ![ParentLayoutName].includes(routeName)) { name.value = routeName; } else { @@ -22,6 +21,7 @@ export function useCache(isPage: boolean) { name.value = matched[len - 2].name as string; } }); + const { getOpenKeepAlive } = useRootSetting(); const getCaches = computed((): string[] => { diff --git a/src/layouts/parent/index.vue b/src/layouts/parent/index.vue deleted file mode 100644 index 0fa6cd62..00000000 --- a/src/layouts/parent/index.vue +++ /dev/null @@ -1,73 +0,0 @@ - - - diff --git a/src/layouts/parent/useTransition.ts b/src/layouts/parent/useTransition.ts deleted file mode 100644 index d768e233..00000000 --- a/src/layouts/parent/useTransition.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting'; - -import { appStore } from '/@/store/modules/app'; -import { tryOnUnmounted } from '/@/utils/helper/vueHelper'; - -export function useTransition() { - function handleAfterEnter() { - const { getOpenPageLoading, getEnableTransition } = useTransitionSetting(); - if (!getOpenPageLoading.value || !getEnableTransition.value) return; - // Close loading after the route switching animation ends - appStore.setPageLoadingAction(false); - } - - tryOnUnmounted(() => { - handleAfterEnter(); - stop(); - }); - - return { - onAfterEnter: handleAfterEnter, - }; -} diff --git a/src/router/constant.ts b/src/router/constant.ts index e0234e42..a0025c7a 100644 --- a/src/router/constant.ts +++ b/src/router/constant.ts @@ -1,5 +1,5 @@ import type { AppRouteRecordRaw } from '/@/router/types'; -import ParentLayout from '/@/layouts/parent/index.vue'; +import ParentLayout from '/@/layouts/page/ParentView.vue'; const EXCEPTION_COMPONENT = () => import('../views/sys/exception/Exception'); @@ -8,11 +8,6 @@ const EXCEPTION_COMPONENT = () => import('../views/sys/exception/Exception'); */ export const LAYOUT = () => import('/@/layouts/default/index'); -/** - * @description: page-layout - */ -export const PAGE_LAYOUT_COMPONENT = () => import('/@/layouts/page/index.vue'); - /** * @description: page-layout */ diff --git a/src/router/guard/index.ts b/src/router/guard/index.ts index 4850542a..66019473 100644 --- a/src/router/guard/index.ts +++ b/src/router/guard/index.ts @@ -1,4 +1,4 @@ -import type { Router } from 'vue-router'; +import { isNavigationFailure, Router } from 'vue-router'; import { Modal, notification } from 'ant-design-vue'; @@ -8,7 +8,7 @@ import { createPageLoadingGuard } from './pageLoadingGuard'; import { useGlobSetting, useProjectSetting } from '/@/hooks/setting'; -import { getIsOpenTab, getRoute } from '/@/router/helper/routeHelper'; +import { getRoute } from '/@/router/helper/routeHelper'; import { setTitle } from '/@/utils/browser'; import { AxiosCanceler } from '/@/utils/http/axios/axiosCancel'; @@ -24,13 +24,10 @@ export function createGuard(router: Router) { if (removeAllHttpPending) { axiosCanceler = new AxiosCanceler(); } + const loadedPageMap = new Map(); - createPageLoadingGuard(router); router.beforeEach(async (to) => { - // Determine whether the tab has been opened - const isOpen = getIsOpenTab(to.fullPath); - to.meta.inTab = isOpen; - + to.meta.loaded = !!loadedPageMap.get(to.path); // Notify routing changes tabStore.commitLastChangeRouteState(getRoute(to)); @@ -47,11 +44,17 @@ export function createGuard(router: Router) { return true; }); - router.afterEach((to) => { + router.afterEach((to, from, failure) => { + loadedPageMap.set(to.path, true); const { t } = useI18n(); // change html title to.name !== REDIRECT_NAME && setTitle(t(to.meta.title), globSetting.title); + + if (isNavigationFailure(failure)) { + console.error('router navigation failed:', failure); + } }); + createPageLoadingGuard(router); createProgressGuard(router); createPermissionGuard(router); } diff --git a/src/router/guard/pageLoadingGuard.ts b/src/router/guard/pageLoadingGuard.ts index 69e8cdd8..9c3dadf8 100644 --- a/src/router/guard/pageLoadingGuard.ts +++ b/src/router/guard/pageLoadingGuard.ts @@ -1,50 +1,32 @@ import type { Router } from 'vue-router'; -import { tabStore } from '/@/store/modules/tab'; import { appStore } from '/@/store/modules/app'; import { userStore } from '/@/store/modules/user'; -import { getParams } from '/@/router/helper/routeHelper'; import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting'; import { unref } from 'vue'; -const { getOpenPageLoading, getEnableTransition } = useTransitionSetting(); +const { getOpenPageLoading } = useTransitionSetting(); export function createPageLoadingGuard(router: Router) { - let isFirstLoad = true; router.beforeEach(async (to) => { - const { openKeepAlive, multiTabsSetting: { show } = {} } = appStore.getProjectConfig; if (!userStore.getTokenState) { return true; } - - if (!unref(getEnableTransition) && unref(getOpenPageLoading)) { - appStore.commitPageLoadingState(true); + if (to.meta.loaded) { return true; } - if (show && openKeepAlive && !isFirstLoad) { - const tabList = tabStore.getTabsState; - - const isOpen = tabList.some((tab) => tab.path === to.path); - appStore.setPageLoadingAction(!isOpen); - } else { + if (unref(getOpenPageLoading)) { appStore.setPageLoadingAction(true); + return true; } + return true; }); - router.afterEach(async (to, from) => { - const realToPath = to.path.replace(getParams(to), ''); - const realFormPath = from.path.replace(getParams(from), ''); - if ( - (!unref(getEnableTransition) && unref(getOpenPageLoading)) || - isFirstLoad || - to.meta.afterCloseLoading || - realToPath === realFormPath - ) { + router.afterEach(async () => { + if (unref(getOpenPageLoading)) { setTimeout(() => { appStore.commitPageLoadingState(false); - }, 110); - isFirstLoad = false; + }, 300); } - return true; }); } diff --git a/src/router/guard/progressGuard.ts b/src/router/guard/progressGuard.ts index a617d7ad..4c73e859 100644 --- a/src/router/guard/progressGuard.ts +++ b/src/router/guard/progressGuard.ts @@ -10,12 +10,14 @@ const { getOpenNProgress } = useTransitionSetting(); export function createProgressGuard(router: Router) { router.beforeEach(async (to) => { - !to.meta.inTab && unref(getOpenNProgress) && NProgress.start(); + if (to.meta.loaded) return true; + unref(getOpenNProgress) && NProgress.start(); return true; }); router.afterEach(async (to) => { - !to.meta.inTab && unref(getOpenNProgress) && NProgress.done(); + if (to.meta.loaded) return true; + unref(getOpenNProgress) && NProgress.done(); return true; }); } diff --git a/src/router/helper/routeHelper.ts b/src/router/helper/routeHelper.ts index 4f286e65..3968f491 100644 --- a/src/router/helper/routeHelper.ts +++ b/src/router/helper/routeHelper.ts @@ -1,8 +1,6 @@ import type { AppRouteModule, AppRouteRecordRaw } from '/@/router/types'; import type { RouteLocationNormalized, RouteRecordNormalized } from 'vue-router'; -import { appStore } from '/@/store/modules/app'; -import { tabStore } from '/@/store/modules/tab'; import { getParentLayout, LAYOUT } from '/@/router/constant'; import dynamicImport from './dynamicImport'; import { cloneDeep } from 'lodash-es'; @@ -48,20 +46,6 @@ export function transformObjToRoute(routeList: AppRouteModul return (routeList as unknown) as T[]; } -/** - * Determine whether the tab has been opened - * @param toPath - */ -export function getIsOpenTab(toPath: string) { - const { openKeepAlive, multiTabsSetting: { show } = {} } = appStore.getProjectConfig; - - if (show && openKeepAlive) { - const tabList = tabStore.getTabsState; - return tabList.some((tab) => tab.path === toPath); - } - return false; -} - export function getParams(data: any = {}) { const { params = {} } = data; let ret = ''; diff --git a/src/router/index.ts b/src/router/index.ts index 2e9d90b8..ad2218ae 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -33,4 +33,8 @@ export function setupRouter(app: App) { createGuard(router); } +router.onError((error) => { + console.error(error); +}); + export default router; diff --git a/src/router/types.d.ts b/src/router/types.d.ts index b85d3ce1..0054c5ad 100644 --- a/src/router/types.d.ts +++ b/src/router/types.d.ts @@ -27,8 +27,6 @@ export interface RouteMeta { // close loading afterCloseLoading?: boolean; - // Is it in the tab - inTab?: boolean; // Carrying parameters carryParam?: boolean; diff --git a/src/settings/projectSetting.ts b/src/settings/projectSetting.ts index ff0d6152..65c5c2d4 100644 --- a/src/settings/projectSetting.ts +++ b/src/settings/projectSetting.ts @@ -119,8 +119,6 @@ const setting: ProjectConfig = { canDrag: true, // Turn on quick actions showQuick: true, - // Maximum number of tab cache - max: 12, }, // Transition Setting diff --git a/src/store/modules/app.ts b/src/store/modules/app.ts index b4b6d61f..1a680b48 100644 --- a/src/store/modules/app.ts +++ b/src/store/modules/app.ts @@ -105,7 +105,7 @@ class App extends VuexModule { // Prevent flicker timeId = setTimeout(() => { this.commitPageLoadingState(loading); - }, 100); + }, 50); } else { this.commitPageLoadingState(loading); clearTimeout(timeId); diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts index 2f361187..7db5c0a1 100644 --- a/src/store/modules/user.ts +++ b/src/store/modules/user.ts @@ -1,4 +1,3 @@ -import { appStore } from './app'; import type { LoginParams, GetUserInfoByUserIdModel, @@ -107,12 +106,7 @@ class User extends VuexModule { // const name = FULL_PAGE_NOT_FOUND_ROUTE.name; // name && router.removeRoute(name); - goHome && - (await router.push(PageEnum.BASE_HOME).then(() => { - setTimeout(() => { - appStore.commitPageLoadingState(false); - }, 30); - })); + goHome && router.push(PageEnum.BASE_HOME); return userInfo; } catch (error) { return null; diff --git a/src/types/config.d.ts b/src/types/config.d.ts index f9f1ed5e..da6e0982 100644 --- a/src/types/config.d.ts +++ b/src/types/config.d.ts @@ -29,8 +29,6 @@ export interface MultiTabsSetting { // 开启快速操作 showQuick: boolean; canDrag: boolean; - // 缓存最大数量 - max: number; } export interface HeaderSetting { diff --git a/src/views/sys/redirect/index.vue b/src/views/sys/redirect/index.vue index 2ef66ec6..20137bcd 100644 --- a/src/views/sys/redirect/index.vue +++ b/src/views/sys/redirect/index.vue @@ -4,15 +4,11 @@