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",
"typescript": "^4.4.2",
"unplugin-element-plus": "^0.1.0",
"vite": "^2.6.5",
"vite": "^2.6.7",
"vite-plugin-mock": "^2.9.6",
"vite-plugin-style-import": "^1.2.1",
"vite-svg-loader": "^2.2.0",

View File

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

View File

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

View File

@ -2,12 +2,14 @@ import {
Router,
createRouter,
RouteComponent,
createWebHashHistory
createWebHashHistory,
RouteRecordNormalized
} from "vue-router";
import { split } from "lodash-es";
import { i18n } from "/@/plugins/i18n";
import NProgress from "/@/utils/progress";
import { openLink } from "/@/utils/link";
import NProgress from "/@/utils/progress";
import { useTimeoutFn } from "@vueuse/core";
import { storageSession, storageLocal } from "/@/utils/storage";
import { usePermissionStoreHook } from "/@/store/modules/permission";
@ -56,6 +58,52 @@ export const filterTree = data => {
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>) => {
if (!arrRoutes || !arrRoutes.length) return;
@ -72,6 +120,7 @@ export const addAsyncRoutes = (arrRoutes: Array<RouteComponent>) => {
return arrRoutes;
};
// 创建路由实例
export const router: Router = createRouter({
history: createWebHashHistory(),
routes: filterTree(ascending(constantRoutes)).concat(...remainingRouter),
@ -90,6 +139,7 @@ export const router: Router = createRouter({
}
});
// 初始化路由
export const initRouter = name => {
return new Promise(resolve => {
getAsyncRoutes({ name }).then(({ info }) => {
@ -122,7 +172,7 @@ export const initRouter = name => {
});
};
// reset router
// 重置路由
export function resetRouter() {
router.getRoutes().forEach(route => {
const { name } = route;
@ -132,9 +182,18 @@ export function resetRouter() {
});
}
// 路由白名单
const whiteList = ["/login", "/register"];
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");
NProgress.start();
const externalLink = to?.redirectedFrom?.fullPath;

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
import { defineStore } from "pinia";
import { store } from "/@/store";
import { cacheType } from "./types";
import { constantRoutesArr, ascending, filterTree } from "/@/router/index";
export const usePermissionStore = defineStore({
@ -8,7 +9,9 @@ export const usePermissionStore = defineStore({
// 静态路由
constantRoutes: constantRoutesArr,
wholeRoutes: [],
buttonAuth: []
buttonAuth: [],
// 缓存页面keepAlive
cachePageList: []
}),
actions: {
asyncActionRoutes(routes) {
@ -33,6 +36,23 @@ export const usePermissionStore = defineStore({
},
async changeSetting(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 {
title: string;
fixedHeader: boolean;
cachedPageList: string[];
}
export const useSettingStore = defineStore({
id: "pure-setting",
state: (): SettingState => ({
title: defaultSettings.title,
fixedHeader: defaultSettings.fixedHeader,
// 需要开启keepalive的页面数组里面放页面的name即可
cachedPageList: ["welcome", "reEditor"]
fixedHeader: defaultSettings.fixedHeader
}),
getters: {
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>
<div class="app-container">
<p>{{ $t("message.hsmenu1") }}</p>
<router-view v-slot="{ Component }">
<transition>
<component :is="Component" />
</transition>
<router-view>
<template #default="{ Component, route }">
<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>
</template>
</router-view>
</div>
</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>
<p style="text-indent: 2em">{{ $t("message.hsmenu1-1") }}</p>
<div>
<p style="text-indent: 2em">{{ $t("message.hsmenu1-1") }}</p>
<el-input v-model="input" />
</div>
</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>
<div>
<p style="text-indent: 2em">{{ $t("message.hsmenu1-2") }}</p>
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
<router-view>
<template #default="{ Component, route }">
<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>
</template>
</router-view>
</div>
</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>
<p style="text-indent: 4em">{{ $t("message.hsmenu1-2-1") }}</p>
<div>
<p style="text-indent: 4em">{{ $t("message.hsmenu1-2-1") }}</p>
<el-input v-model="input" />
</div>
</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>
<p style="text-indent: 4em">{{ $t("message.hsmenu1-2-2") }}</p>
<div>
<p style="text-indent: 4em">{{ $t("message.hsmenu1-2-2") }}</p>
<el-input v-model="input" />
</div>
</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>
<p style="text-indent: 2em">{{ $t("message.hsmenu1-3") }}</p>
<div>
<p style="text-indent: 2em">{{ $t("message.hsmenu1-3") }}</p>
<el-input v-model="input" />
</div>
</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>
<p class="app-container">{{ $t("message.hsmenu2") }}</p>
<div class="app-container">
<p>{{ $t("message.hsmenu2") }}</p>
<el-input v-model="input" />
</div>
</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"
svgo "^2.3.0"
vite@^2.6.5:
version "2.6.5"
resolved "https://registry.npmjs.org/vite/-/vite-2.6.5.tgz#c4d25972e2f7371e682da86828722ddf5126f3d1"
integrity sha512-vavXMChDUb4Oh4YunrK9BrH5Ox74cu0eOp0VuyI/iqFz1FqbWD72So2c9I87lLL2n0+6tFPV5ijow60KrtxuZg==
vite@^2.6.7:
version "2.6.7"
resolved "https://registry.npmjs.org/vite/-/vite-2.6.7.tgz#e15c1d8327950720b5d7c4ec3fb36a5a58ccf7cb"
integrity sha512-ewk//jve9k6vlU8PfJmWUHN8k0YYdw4VaKOMvoQ3nT2Pb6k5OSMKQi4jPOzVH/TlUqMsCrq7IJ80xcuDDVyigg==
dependencies:
esbuild "^0.13.2"
postcss "^8.3.8"