feat: add persistence of tabs

This commit is contained in:
xiaoxian521 2021-04-21 05:08:39 +08:00
parent 762833e545
commit 62ad9e6f40
5 changed files with 114 additions and 47 deletions

View File

@ -20,12 +20,7 @@
</app-link> </app-link>
</template> </template>
<el-submenu <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
v-else
ref="subMenu"
:index="resolvePath(item.path)"
popper-append-to-body
>
<template #title> <template #title>
<i :class="item.meta.icon"></i> <i :class="item.meta.icon"></i>
<span>{{ $t(item.meta.title) }}</span> <span>{{ $t(item.meta.title) }}</span>
@ -53,16 +48,16 @@ export default defineComponent({
props: { props: {
item: { item: {
type: Object as PropType<RouteRecordRaw>, type: Object as PropType<RouteRecordRaw>,
required: true, required: true
}, },
isNest: { isNest: {
type: Boolean, type: Boolean,
default: false, default: false
}, },
basePath: { basePath: {
type: String, type: String,
default: "", default: ""
}, }
}, },
setup(props) { setup(props) {
const onlyOneChild = ref<RouteRecordRaw>({} as any); const onlyOneChild = ref<RouteRecordRaw>({} as any);
@ -71,7 +66,7 @@ export default defineComponent({
children: RouteRecordRaw[] = [], children: RouteRecordRaw[] = [],
parent: RouteRecordRaw parent: RouteRecordRaw
) { ) {
const showingChildren = children.filter((item) => { const showingChildren = children.filter(item => {
if (item.hidden) { if (item.hidden) {
return false; return false;
} else { } else {
@ -96,6 +91,6 @@ export default defineComponent({
}; };
return { hasOneShowingChild, resolvePath, onlyOneChild }; return { hasOneShowingChild, resolvePath, onlyOneChild };
}, }
}); });
</script> </script>

View File

@ -22,12 +22,13 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed, defineComponent } from "vue"; import { computed, defineComponent, unref, nextTick } from "vue";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import { useStore } from "vuex"; import { useStore } from "vuex";
import SidebarItem from "./SidebarItem.vue"; import SidebarItem from "./SidebarItem.vue";
import { algorithm } from "../../../utils/algorithm"; import { algorithm } from "../../../utils/algorithm";
import { useDynamicRoutesHook } from "../tag/tagsHook"; import { useDynamicRoutesHook } from "../tag/tagsHook";
import { emitter } from "/@/utils/mitt";
export default defineComponent({ export default defineComponent({
name: "sidebar", name: "sidebar",
@ -55,15 +56,27 @@ export default defineComponent({
if (parentPathIndex > 0) { if (parentPathIndex > 0) {
parentPath = indexPath.slice(0, parentPathIndex); parentPath = indexPath.slice(0, parentPathIndex);
} }
dynamicRouteTags(indexPath, parentPath); //
function findCurrentRoute(routes) {
return routes.map((item, key) => {
if (item.path === indexPath) {
dynamicRouteTags(indexPath, parentPath, item);
} else {
if (item.children) findCurrentRoute(item.children);
}
});
return;
}
findCurrentRoute(algorithm.increaseIndexes(router));
emitter.emit("changLayoutRoute", indexPath);
}; };
return { return {
routes: computed(() => algorithm.increaseIndexes(router)), routes: computed(() => algorithm.increaseIndexes(router)),
activeMenu, activeMenu,
isCollapse: computed(() => !store.getters.sidebar.opened), isCollapse: computed(() => !store.getters.sidebar.opened),
menuSelect, menuSelect
}; };
}, }
}); });
</script> </script>

View File

@ -42,11 +42,11 @@
<script> <script>
import { useDynamicRoutesHook } from "./tagsHook" import { useDynamicRoutesHook } from "./tagsHook"
import { useRoute, useRouter } from "vue-router" import { useRoute, useRouter } from "vue-router"
import { ref, watchEffect, onBeforeMount, unref } from "vue" import { ref, watchEffect, onBeforeMount, unref, nextTick } from "vue"
import { storageLocal } from "/@/utils/storage" import { storageLocal } from "/@/utils/storage"
import { emitter } from "/@/utils/mitt" import { emitter } from "/@/utils/mitt"
import { toggleClass, removeClass } from "/@/utils/operate" import { toggleClass, removeClass } from "/@/utils/operate"
import { nextTick } from 'vue' import { homeRoute } from "./type"
let refreshDiv = "refresh-div" let refreshDiv = "refresh-div"
export default { export default {
@ -73,20 +73,25 @@ export default {
icon: "el-icon-more", icon: "el-icon-more",
text: "关闭其他标签页", text: "关闭其他标签页",
divided: true, divided: true,
disabled: false disabled: unref(routesLength) > 2 ? false : true
}, },
{ {
icon: "el-icon-minus", icon: "el-icon-minus",
text: "关闭全部标签页", text: "关闭全部标签页",
divided: false, divided: false,
disabled: false disabled: unref(routesLength) > 1 ? false : true
}, },
]) ])
function deleteMenu(item) { function deleteMenu(item) {
let tagslen = storageLocal.getItem("routesInStorage").length - 1 let tagslen = storageLocal.getItem("routesInStorage").length
if (tagslen === 1) { if (tagslen === 2) {
tagsViews.value[1].disabled = true Array.from([1, 2, 3]).forEach(v => {
tagsViews.value[v].disabled = true
})
}
if (tagslen === 3) {
tagsViews.value[2].disabled = true
} }
deleteDynamicTag(item, route.path) deleteDynamicTag(item, route.path)
} }
@ -115,6 +120,7 @@ export default {
function onClickDrop(key, item) { function onClickDrop(key, item) {
if (item.disabled) return if (item.disabled) return
//
switch (key) { switch (key) {
case 0: case 0:
// //
@ -122,25 +128,22 @@ export default {
break break
case 1: case 1:
// //
deleteMenu({ meta: route.meta, path: route.path }) deleteMenu({ path: route.path, meta: route.meta })
break break
case 2: case 2:
// //
dRoutes.value = [homeRoute, { path: route.path, meta: route.meta }]
storageLocal.setItem("routesInStorage", dRoutes.value)
tagsViews.value[2].disabled = true
break break
case 3: case 3:
// //
dRoutes.value = [{ dRoutes.value = [homeRoute]
path: "/welcome",
meta: {
title: "home",
icon: "el-icon-s-home",
showLink: true,
savedPosition: false,
},
}]
storageLocal.setItem("routesInStorage", dRoutes.value) storageLocal.setItem("routesInStorage", dRoutes.value)
router.push("/welcome") router.push("/welcome")
tagsViews.value[1].disabled = true Array.from([1, 2, 3]).forEach(v => {
tagsViews.value[v].disabled = true
})
break break
} }
} }
@ -150,6 +153,20 @@ export default {
if (unref(showTags) === key) return if (unref(showTags) === key) return
showTags.value = key showTags.value = key
}) })
emitter.on("changLayoutRoute", (indexPath) => {
let currentLen = storageLocal.getItem("routesInStorage").length
if (currentLen === 1) {
Array.from([1, 3]).forEach(v => {
tagsViews.value[v].disabled = false
})
}
if (currentLen >= 2) {
Array.from([1, 2, 3]).forEach(v => {
tagsViews.value[v].disabled = false
})
}
})
}) })
return { return {

View File

@ -1,6 +1,7 @@
import { reactive, toRefs, nextTick, computed } from "vue"; import { reactive, toRefs, unref, nextTick, computed } from "vue";
import { storageLocal } from "/@/utils/storage"; import { storageLocal } from "/@/utils/storage";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { homeRoute } from "./type";
interface InterDynamic { interface InterDynamic {
dRoutes: object[]; dRoutes: object[];
@ -24,21 +25,57 @@ let dynamic: InterDynamic = reactive({
export function useDynamicRoutesHook() { export function useDynamicRoutesHook() {
const router = useRouter(); const router = useRouter();
const routesLength = computed(() => {
return storageLocal.getItem("routesInStorage")
? storageLocal.getItem("routesInStorage").length
: 0;
});
// 返回当前路由组成的数组
const routesStorageLists = computed(() => {
return storageLocal.getItem("routesInStorage")
? storageLocal.getItem("routesInStorage")
: [];
});
/** /**
* @param value string menu对应的路由path * @param value string menu对应的路由path
* @param parentPath string * @param parentPath string
*/ */
const dynamicRouteTags = (value: string, parentPath: string): void => { const dynamicRouteTags = (
value: string,
parentPath: string,
route: any
): void => {
nextTick(() => {
if (unref(routesStorageLists).length > 2) {
dynamic.dRoutes = unref(routesStorageLists);
return;
}
});
const hasValue = dynamic.dRoutes.some((item: any) => { const hasValue = dynamic.dRoutes.some((item: any) => {
return item.path === value; return item.path === value;
}); });
if (route) {
let ramStorage = storageLocal.getItem("routesInStorage");
nextTick(() => {
let currentIndex = ramStorage.findIndex((v) => v.path === route.path);
if (currentIndex !== -1) return;
ramStorage.push({ path: route.path, meta: route.meta });
storageLocal.setItem("routesInStorage", ramStorage);
});
}
function concatPath(arr: object[], value: string, parentPath: string) { function concatPath(arr: object[], value: string, parentPath: string) {
if (!hasValue) { if (!hasValue) {
arr.forEach((arrItem: any) => { arr.forEach((arrItem: any) => {
let pathConcat = parentPath + "/" + arrItem.path; let pathConcat = parentPath + "/" + arrItem.path;
if (arrItem.path === value || pathConcat === value) { if (arrItem.path === value || pathConcat === value) {
dynamic.dRoutes.push({ path: value, meta: arrItem.meta }); dynamic.dRoutes.push({ path: value, meta: arrItem.meta });
unref(routesLength) === 0
? storageLocal.setItem("routesInStorage", dynamic.dRoutes)
: [];
} else { } else {
if (arrItem.children && arrItem.children.length > 0) { if (arrItem.children && arrItem.children.length > 0) {
concatPath(arrItem.children, value, parentPath); concatPath(arrItem.children, value, parentPath);
@ -48,12 +85,6 @@ export function useDynamicRoutesHook() {
} }
} }
concatPath(router.options.routes, value, parentPath); concatPath(router.options.routes, value, parentPath);
// if (storageLocal.getItem("routesInStorage") && storageLocal.getItem("routesInStorage").length > 2) {
// let lens = storageLocal.getItem("routesInStorage").length
// let itemss = storageLocal.getItem("routesInStorage")[lens - 1]
// dynamic.dRoutes.push({ path: itemss.path, meta: itemss.meta })
// }
storageLocal.setItem("routesInStorage", dynamic.dRoutes);
}; };
/** /**
* @param value any tag路由 * @param value any tag路由
@ -76,16 +107,12 @@ export function useDynamicRoutesHook() {
}); });
} }
}; };
const routesLength = computed(() => {
return storageLocal.getItem("routesInStorage")
? storageLocal.getItem("routesInStorage").length
: 0;
});
return { return {
...toRefs(dynamic), ...toRefs(dynamic),
dynamicRouteTags, dynamicRouteTags,
deleteDynamicTag, deleteDynamicTag,
routesLength, routesLength,
routesStorageLists,
}; };
} }

View File

@ -0,0 +1,15 @@
interface RouteModel {
readonly path: string;
readonly meta: object;
}
// 固定首页路由
export const homeRoute: RouteModel = {
path: "/welcome",
meta: {
title: "home",
icon: "el-icon-s-home",
showLink: true,
savedPosition: false,
},
};