头部面包屑改成多页签

跟着vue3.x + ts + vue-router + pinia简易多页签方案实现一个头部面包屑改成多页签路由缓存功能。

由于菜单存在一级菜单和二级菜单,使用缓存时一定要给动态组件一个key值,否则路由均嵌套在一个页面内。

此时还有另外一个问题,在keep-alive外层过渡动画transition,此时的动画对于二级菜单是无效的,并且过度动画里需要对元素有一个创建和销毁的过程动画才能生效。

而且keep-alive内部只能缓存第一级根元素,如果用transition包裹动态组件,缓存动态路由组件就会失效了。

故此时不使用过度动画了,但缓存好了,如何关闭呢?如何清除缓存呢。此时可能想到keep-aliveinclude

但项目写好的页面已经存在很多使用setup语法糖script标签未命名的页面,不可能将所有页面重构成非setup语法糖的写法。

我在vue3的issue里找到加script标签的解决方案,但是还是不想给每个页面添加也个新的名称。

故给缓存的动态组件绑定路由的完整路径fullName,并且这个key末尾再加一个随机数,这样路由标签就可以关闭了。

其原理是其实缓存组件并没有销毁掉,只是处于失活状态,在重新打开路由时,创建了一个新的key值,修改的是随机数,故重新创建了一个动态路由组件进行渲染,从而达到刷新的目的。

但缓存的组件越来越多怎么办?此时max属性非常重要了,其缓存超过最大数值时,会自动销毁最前创建的缓存。

1
2
3
4
5
6
<router-view v-slot="{ Component,route}">
<keep-alive :max="20">
<component :is="Component"
:key="isNeedKeep[route.fullPath]"></component>
</keep-alive>
</router-view>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<script setup lang="ts">

const isNeedKeep = reactive({});
watch(
() => tabs,
() => {
const tabsFullpath = tabs.map((i) => i.fullPath);
Object.keys(isNeedKeep).forEach((i) => {
if (!tabsFullpath.includes(i)) {
const ran = Math.random().toFixed(5);
isNeedKeep[i] = `${isNeedKeep[i]}${ran}`;
}
});
},
{ deep: true }
);

onBeforeMount(() => {
const currentPath = route.fullPath;
if (!isNeedKeep[currentPath]) {
isNeedKeep[currentPath] = `${currentPath}_`;
}
});
</script>