背景
领导要求后台管理系统实现tabs标签页功能,每个页面打开后需显示标签并缓存页面。
使用Pinia
定义一个tagStore
保存路由路径,并结合keepalive
实现缓存。
但是遇上了缓存的页面组件需要命名才能生效的问题,但是老系统页面组件太多了
给每个组件都命名是不存在的 🙃。
实现页面缓存示例
vue_sfc
<tabs/> <!-- 标签栏组件 实现省略:就是标签的增删改查和tagStore.tags数组的维护 -->
<router-view v-slot="{ Component, route }">
<keep-alive :include="keepAliveNames">
<component :is="Component" :key="route.fullPath"/>
</keep-alive>
</router-view>
<script setup>
import { computed } from 'vue';
import { useTagStore } from '@/stores/tagStore';
const tagStore = useTagStore();
const keepAliveNames = computed(() => {
return tagStore.tags.filter((item) => item.keepAlive).map((item) => item.name);
});
</script>
遇到的问题
配置后缓存不生效,原因是页面组件未设置名称,而keep-alive
需要组件有名称。
解决方案
后台有好几百个页面,不可能手动设置每个页面的名称。系统的菜单是动态配置的,接口返回菜单名称和组件地址。在配置菜单时添加name
字段,并确保后端接口校验其唯一性。
const modules = import.meta.glob(['../pages/**/*.vue']);
// 遍历后端返回的菜单并且动态添加路由(省略..)
// 在添加路由时,给每个路由配置component
// route 就是根据后端接口返回的菜单组装的数据。后面需要被添加到路由:router.push(route)
route.component = () => {
// modules[`../pages/${route.routeName}/index.vue`] 形如: ()=>import('xxx.vue')
return modules[`../pages/${routeName}/index.vue`]().then((m) => {
if (route.name && m && m.default) {
m.default.name = route.name;
}
return m;
});
};
总结
利用Vue Router
的路由接收Promise
的特性,按需加载页面路由组件,并在加载后为组件命名,配合keepalive
实现页面缓存。