perf/route (#54)

* perf: router

* perf: route
This commit is contained in:
啝裳 2021-10-12 23:33:13 +08:00 committed by GitHub
parent 0408fa6f96
commit a31d154806
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 257 additions and 38 deletions

View File

@ -92,7 +92,7 @@
"stylelint-order": "^4.1.0", "stylelint-order": "^4.1.0",
"typescript": "^4.4.2", "typescript": "^4.4.2",
"unplugin-element-plus": "^0.1.0", "unplugin-element-plus": "^0.1.0",
"vite": "^2.6.5", "vite": "^2.6.7",
"vite-plugin-mock": "^2.9.6", "vite-plugin-mock": "^2.9.6",
"vite-plugin-style-import": "^1.2.1", "vite-plugin-style-import": "^1.2.1",
"vite-svg-loader": "^2.2.0", "vite-svg-loader": "^2.2.0",

View File

@ -1,17 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, unref, computed, getCurrentInstance } from "vue"; import { ref, getCurrentInstance } from "vue";
import { useSettingStoreHook } from "/@/store/modules/settings"; import { usePermissionStoreHook } from "/@/store/modules/permission";
const keepAlive: Boolean = ref( const keepAlive: Boolean = ref(
getCurrentInstance().appContext.config.globalProperties.$config?.KeepAlive getCurrentInstance().appContext.config.globalProperties.$config?.KeepAlive
); );
const getCachedPageList = computed((): string[] => {
if (!unref(keepAlive)) {
return [];
}
return useSettingStoreHook().cachedPageList;
});
</script> </script>
<template> <template>
@ -19,7 +12,10 @@ const getCachedPageList = computed((): string[] => {
<router-view> <router-view>
<template #default="{ Component, route }"> <template #default="{ Component, route }">
<transition appear name="fade-transform" mode="out-in"> <transition appear name="fade-transform" mode="out-in">
<keep-alive v-if="keepAlive" :include="getCachedPageList"> <keep-alive
v-if="keepAlive"
:include="usePermissionStoreHook().cachePageList"
>
<component :is="Component" :key="route.fullPath" /> <component :is="Component" :key="route.fullPath" />
</keep-alive> </keep-alive>
<component v-else :is="Component" :key="route.fullPath" /> <component v-else :is="Component" :key="route.fullPath" />

View File

@ -12,8 +12,10 @@ import {
import { RouteConfigs, relativeStorageType, tagsViewsType } from "../../types"; import { RouteConfigs, relativeStorageType, tagsViewsType } from "../../types";
import { emitter } from "/@/utils/mitt"; import { emitter } from "/@/utils/mitt";
import { templateRef } from "@vueuse/core"; import { templateRef } from "@vueuse/core";
import { handleAliveRoute } from "/@/router";
import { storageLocal } from "/@/utils/storage"; import { storageLocal } from "/@/utils/storage";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import { usePermissionStoreHook } from "/@/store/modules/permission";
import { toggleClass, removeClass, hasClass } from "/@/utils/operate"; import { toggleClass, removeClass, hasClass } from "/@/utils/operate";
import close from "/@/assets/svg/close.svg"; import close from "/@/assets/svg/close.svg";
@ -171,6 +173,8 @@ function deleteDynamicTag(obj: any, current: any, tag?: string) {
relativeStorage.routesInStorage = routerArrays; relativeStorage.routesInStorage = routerArrays;
} }
router.push(obj.path); router.push(obj.path);
//
handleAliveRoute(route.matched, "delete");
}; };
if (tag === "other") { if (tag === "other") {
@ -253,7 +257,9 @@ function onClickDrop(key, item, selectRoute?: RouteConfigs) {
// //
routerArrays.splice(1, routerArrays.length); routerArrays.splice(1, routerArrays.length);
relativeStorage.routesInStorage = routerArrays; relativeStorage.routesInStorage = routerArrays;
usePermissionStoreHook().clearAllCachePage();
router.push("/welcome"); router.push("/welcome");
break; break;
} }
setTimeout(() => { setTimeout(() => {

View File

@ -2,12 +2,14 @@ import {
Router, Router,
createRouter, createRouter,
RouteComponent, RouteComponent,
createWebHashHistory createWebHashHistory,
RouteRecordNormalized
} from "vue-router"; } from "vue-router";
import { split } from "lodash-es"; import { split } from "lodash-es";
import { i18n } from "/@/plugins/i18n"; import { i18n } from "/@/plugins/i18n";
import NProgress from "/@/utils/progress";
import { openLink } from "/@/utils/link"; import { openLink } from "/@/utils/link";
import NProgress from "/@/utils/progress";
import { useTimeoutFn } from "@vueuse/core";
import { storageSession, storageLocal } from "/@/utils/storage"; import { storageSession, storageLocal } from "/@/utils/storage";
import { usePermissionStoreHook } from "/@/store/modules/permission"; import { usePermissionStoreHook } from "/@/store/modules/permission";
@ -56,6 +58,52 @@ export const filterTree = data => {
return newTree; return newTree;
}; };
// 从路由中提取keepAlive为true的name组成数组此处本项目中并没有用到只是暴露个方法
export const getAliveRoute = () => {
const alivePageList = [];
const recursiveSearch = treeLists => {
if (!treeLists || !treeLists.length) {
return;
}
for (let i = 0; i < treeLists.length; i++) {
if (treeLists[i]?.meta?.keepAlive) alivePageList.push(treeLists[i].name);
recursiveSearch(treeLists[i].children);
}
};
recursiveSearch(router.options.routes);
return alivePageList;
};
// 处理缓存路由(添加、删除、刷新)
export const handleAliveRoute = (
matched: RouteRecordNormalized[],
mode?: string
) => {
switch (mode) {
case "add":
matched.forEach(v => {
usePermissionStoreHook().cacheOperate({ mode: "add", name: v.name });
});
break;
case "delete":
usePermissionStoreHook().cacheOperate({
mode: "delete",
name: matched[matched.length - 1].name
});
break;
default:
usePermissionStoreHook().cacheOperate({
mode: "delete",
name: matched[matched.length - 1].name
});
useTimeoutFn(() => {
matched.forEach(v => {
usePermissionStoreHook().cacheOperate({ mode: "add", name: v.name });
});
}, 100);
}
};
// 过滤后端传来的动态路由 重新生成规范路由 // 过滤后端传来的动态路由 重新生成规范路由
export const addAsyncRoutes = (arrRoutes: Array<RouteComponent>) => { export const addAsyncRoutes = (arrRoutes: Array<RouteComponent>) => {
if (!arrRoutes || !arrRoutes.length) return; if (!arrRoutes || !arrRoutes.length) return;
@ -72,6 +120,7 @@ export const addAsyncRoutes = (arrRoutes: Array<RouteComponent>) => {
return arrRoutes; return arrRoutes;
}; };
// 创建路由实例
export const router: Router = createRouter({ export const router: Router = createRouter({
history: createWebHashHistory(), history: createWebHashHistory(),
routes: filterTree(ascending(constantRoutes)).concat(...remainingRouter), routes: filterTree(ascending(constantRoutes)).concat(...remainingRouter),
@ -90,6 +139,7 @@ export const router: Router = createRouter({
} }
}); });
// 初始化路由
export const initRouter = name => { export const initRouter = name => {
return new Promise(resolve => { return new Promise(resolve => {
getAsyncRoutes({ name }).then(({ info }) => { getAsyncRoutes({ name }).then(({ info }) => {
@ -122,7 +172,7 @@ export const initRouter = name => {
}); });
}; };
// reset router // 重置路由
export function resetRouter() { export function resetRouter() {
router.getRoutes().forEach(route => { router.getRoutes().forEach(route => {
const { name } = route; const { name } = route;
@ -132,9 +182,18 @@ export function resetRouter() {
}); });
} }
// 路由白名单
const whiteList = ["/login", "/register"]; const whiteList = ["/login", "/register"];
router.beforeEach((to, _from, next) => { router.beforeEach((to, _from, next) => {
if (to.meta?.keepAlive) {
const newMatched = to.matched;
handleAliveRoute(newMatched, "add");
// 页面整体刷新和点击标签页刷新
if (_from.name === undefined || _from.name === "redirect") {
handleAliveRoute(newMatched);
}
}
const name = storageSession.getItem("info"); const name = storageSession.getItem("info");
NProgress.start(); NProgress.start();
const externalLink = to?.redirectedFrom?.fullPath; const externalLink = to?.redirectedFrom?.fullPath;

View File

@ -20,6 +20,7 @@ const componentsRouter = {
meta: { meta: {
title: "message.hsvideo", title: "message.hsvideo",
showLink: true, showLink: true,
keepAlive: true,
savedPosition: true savedPosition: true
} }
}, },
@ -30,6 +31,7 @@ const componentsRouter = {
meta: { meta: {
title: "message.hsmap", title: "message.hsmap",
showLink: true, showLink: true,
keepAlive: true,
savedPosition: true savedPosition: true
} }
}, },

View File

@ -2,7 +2,7 @@ import Layout from "/@/layout/index.vue";
const editorRouter = { const editorRouter = {
path: "/editor", path: "/editor",
name: "editor", name: "reEditor",
component: Layout, component: Layout,
redirect: "/editor/index", redirect: "/editor/index",
meta: { meta: {
@ -15,11 +15,12 @@ const editorRouter = {
children: [ children: [
{ {
path: "/editor/index", path: "/editor/index",
name: "editor", name: "reEditor",
component: () => import("/@/views/editor/index.vue"), component: () => import("/@/views/editor/index.vue"),
meta: { meta: {
title: "message.hseditor", title: "message.hseditor",
showLink: true, showLink: true,
keepAlive: true,
savedPosition: true savedPosition: true
} }
} }

View File

@ -20,6 +20,7 @@ const nestedRouter = {
meta: { meta: {
title: "message.hsmenu1", title: "message.hsmenu1",
showLink: true, showLink: true,
keepAlive: true,
savedPosition: false savedPosition: false
}, },
redirect: "/nested/menu1/menu1-1", redirect: "/nested/menu1/menu1-1",
@ -31,6 +32,7 @@ const nestedRouter = {
meta: { meta: {
title: "message.hsmenu1-1", title: "message.hsmenu1-1",
showLink: true, showLink: true,
keepAlive: true,
savedPosition: false savedPosition: false
} }
}, },
@ -42,6 +44,7 @@ const nestedRouter = {
meta: { meta: {
title: "message.hsmenu1-2", title: "message.hsmenu1-2",
showLink: true, showLink: true,
keepAlive: true,
savedPosition: false savedPosition: false
}, },
children: [ children: [
@ -53,6 +56,7 @@ const nestedRouter = {
meta: { meta: {
title: "message.hsmenu1-2-1", title: "message.hsmenu1-2-1",
showLink: true, showLink: true,
keepAlive: true,
savedPosition: false savedPosition: false
} }
}, },
@ -64,6 +68,7 @@ const nestedRouter = {
meta: { meta: {
title: "message.hsmenu1-2-2", title: "message.hsmenu1-2-2",
showLink: true, showLink: true,
keepAlive: true,
savedPosition: false savedPosition: false
} }
} }
@ -76,6 +81,7 @@ const nestedRouter = {
meta: { meta: {
title: "message.hsmenu1-3", title: "message.hsmenu1-3",
showLink: true, showLink: true,
keepAlive: true,
savedPosition: false savedPosition: false
} }
} }
@ -88,6 +94,7 @@ const nestedRouter = {
meta: { meta: {
title: "message.hsmenu2", title: "message.hsmenu2",
showLink: true, showLink: true,
keepAlive: true,
savedPosition: false savedPosition: false
} }
} }

View File

@ -1,5 +1,6 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { store } from "/@/store"; import { store } from "/@/store";
import { cacheType } from "./types";
import { constantRoutesArr, ascending, filterTree } from "/@/router/index"; import { constantRoutesArr, ascending, filterTree } from "/@/router/index";
export const usePermissionStore = defineStore({ export const usePermissionStore = defineStore({
@ -8,7 +9,9 @@ export const usePermissionStore = defineStore({
// 静态路由 // 静态路由
constantRoutes: constantRoutesArr, constantRoutes: constantRoutesArr,
wholeRoutes: [], wholeRoutes: [],
buttonAuth: [] buttonAuth: [],
// 缓存页面keepAlive
cachePageList: []
}), }),
actions: { actions: {
asyncActionRoutes(routes) { asyncActionRoutes(routes) {
@ -33,6 +36,23 @@ export const usePermissionStore = defineStore({
}, },
async changeSetting(routes) { async changeSetting(routes) {
await this.asyncActionRoutes(routes); await this.asyncActionRoutes(routes);
},
cacheOperate({ mode, name }: cacheType) {
switch (mode) {
case "add":
this.cachePageList.push(name);
this.cachePageList = [...new Set(this.cachePageList)];
break;
case "delete":
// eslint-disable-next-line no-case-declarations
const delIndex = this.cachePageList.findIndex(v => v === name);
this.cachePageList.splice(delIndex, 1);
break;
}
},
// 清空缓存页面
clearAllCachePage() {
this.cachePageList = [];
} }
} }
}); });

View File

@ -5,16 +5,13 @@ import { store } from "/@/store";
interface SettingState { interface SettingState {
title: string; title: string;
fixedHeader: boolean; fixedHeader: boolean;
cachedPageList: string[];
} }
export const useSettingStore = defineStore({ export const useSettingStore = defineStore({
id: "pure-setting", id: "pure-setting",
state: (): SettingState => ({ state: (): SettingState => ({
title: defaultSettings.title, title: defaultSettings.title,
fixedHeader: defaultSettings.fixedHeader, fixedHeader: defaultSettings.fixedHeader
// 需要开启keepalive的页面数组里面放页面的name即可
cachedPageList: ["welcome", "reEditor"]
}), }),
getters: { getters: {
getTitle() { getTitle() {

View File

@ -0,0 +1,6 @@
import { RouteRecordName } from "vue-router";
export type cacheType = {
mode: string;
name?: RouteRecordName;
};

View File

@ -1,10 +1,35 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<p>{{ $t("message.hsmenu1") }}</p> <p>{{ $t("message.hsmenu1") }}</p>
<router-view v-slot="{ Component }"> <router-view>
<transition> <template #default="{ Component, route }">
<component :is="Component" /> <transition appear name="fade-transform" mode="out-in">
<keep-alive
v-if="keepAlive"
:include="usePermissionStoreHook().cachePageList"
>
<component :is="Component" :key="route.fullPath" />
</keep-alive>
<component v-else :is="Component" :key="route.fullPath" />
</transition> </transition>
</template>
</router-view> </router-view>
</div> </div>
</template> </template>
<script lang="ts">
import { ref, getCurrentInstance } from "vue";
import { usePermissionStoreHook } from "/@/store/modules/permission";
export default {
name: "Menu1",
setup() {
const keepAlive: Boolean = ref(
getCurrentInstance().appContext.config.globalProperties.$config?.KeepAlive
);
return {
keepAlive,
usePermissionStoreHook
};
}
};
</script>

View File

@ -1,3 +1,18 @@
<template> <template>
<div>
<p style="text-indent: 2em">{{ $t("message.hsmenu1-1") }}</p> <p style="text-indent: 2em">{{ $t("message.hsmenu1-1") }}</p>
<el-input v-model="input" />
</div>
</template> </template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
name: "Menu1-1",
setup() {
return {
input: ref("")
};
}
});
</script>

View File

@ -1,10 +1,35 @@
<template> <template>
<div> <div>
<p style="text-indent: 2em">{{ $t("message.hsmenu1-2") }}</p> <p style="text-indent: 2em">{{ $t("message.hsmenu1-2") }}</p>
<router-view v-slot="{ Component }"> <router-view>
<keep-alive> <template #default="{ Component, route }">
<component :is="Component" /> <transition appear name="fade-transform" mode="out-in">
<keep-alive
v-if="keepAlive"
:include="usePermissionStoreHook().cachePageList"
>
<component :is="Component" :key="route.fullPath" />
</keep-alive> </keep-alive>
<component v-else :is="Component" :key="route.fullPath" />
</transition>
</template>
</router-view> </router-view>
</div> </div>
</template> </template>
<script lang="ts">
import { ref, getCurrentInstance } from "vue";
import { usePermissionStoreHook } from "/@/store/modules/permission";
export default {
name: "Menu1-2",
setup() {
const keepAlive: Boolean = ref(
getCurrentInstance().appContext.config.globalProperties.$config?.KeepAlive
);
return {
keepAlive,
usePermissionStoreHook
};
}
};
</script>

View File

@ -1,3 +1,18 @@
<template> <template>
<div>
<p style="text-indent: 4em">{{ $t("message.hsmenu1-2-1") }}</p> <p style="text-indent: 4em">{{ $t("message.hsmenu1-2-1") }}</p>
<el-input v-model="input" />
</div>
</template> </template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
name: "Menu1-2-1",
setup() {
return {
input: ref("")
};
}
});
</script>

View File

@ -1,3 +1,18 @@
<template> <template>
<div>
<p style="text-indent: 4em">{{ $t("message.hsmenu1-2-2") }}</p> <p style="text-indent: 4em">{{ $t("message.hsmenu1-2-2") }}</p>
<el-input v-model="input" />
</div>
</template> </template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
name: "Menu1-2-2",
setup() {
return {
input: ref("")
};
}
});
</script>

View File

@ -1,3 +1,18 @@
<template> <template>
<div>
<p style="text-indent: 2em">{{ $t("message.hsmenu1-3") }}</p> <p style="text-indent: 2em">{{ $t("message.hsmenu1-3") }}</p>
<el-input v-model="input" />
</div>
</template> </template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
name: "Menu1-3",
setup() {
return {
input: ref("")
};
}
});
</script>

View File

@ -1,3 +1,18 @@
<template> <template>
<p class="app-container">{{ $t("message.hsmenu2") }}</p> <div class="app-container">
<p>{{ $t("message.hsmenu2") }}</p>
<el-input v-model="input" />
</div>
</template> </template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
name: "Menu2",
setup() {
return {
input: ref("")
};
}
});
</script>

View File

@ -4646,10 +4646,10 @@ vite-svg-loader@^2.2.0:
"@vue/compiler-sfc" "^3.0.11" "@vue/compiler-sfc" "^3.0.11"
svgo "^2.3.0" svgo "^2.3.0"
vite@^2.6.5: vite@^2.6.7:
version "2.6.5" version "2.6.7"
resolved "https://registry.npmjs.org/vite/-/vite-2.6.5.tgz#c4d25972e2f7371e682da86828722ddf5126f3d1" resolved "https://registry.npmjs.org/vite/-/vite-2.6.7.tgz#e15c1d8327950720b5d7c4ec3fb36a5a58ccf7cb"
integrity sha512-vavXMChDUb4Oh4YunrK9BrH5Ox74cu0eOp0VuyI/iqFz1FqbWD72So2c9I87lLL2n0+6tFPV5ijow60KrtxuZg== integrity sha512-ewk//jve9k6vlU8PfJmWUHN8k0YYdw4VaKOMvoQ3nT2Pb6k5OSMKQi4jPOzVH/TlUqMsCrq7IJ80xcuDDVyigg==
dependencies: dependencies:
esbuild "^0.13.2" esbuild "^0.13.2"
postcss "^8.3.8" postcss "^8.3.8"