vue3 keep-alive缓存 多层嵌套路由 onMounted多次触发及根据不同情况可能需刷新缓存页面的问题
1. onMounted多次触发
原因
一级路由找不到路由对应的route.meta.keepAlive,导出在访问一级路由和子路由都触发生命周期加载
解决方案
在外层router-view的时候,判断获取的route层级,如果不是一级目录则通过当前route获取后再使用,接口调用不要写在onMounted,需要写到onActivated中
一级页面代码
<router-view v-slot="{ Component, route }">
<keep-alive>
<component
:is="Component"
:key="getFirstLevelRoute(route).name"
v-if="getFirstLevelRoute(route).meta.keepAlive"
></component>
</keep-alive>
<component
:is="Component"
:key="getFirstLevelRoute(route).name"
v-if="!getFirstLevelRoute(route).meta.keepAlive"
></component>
</router-view>
const getFirstLevelRoute = route => {
if (!Array.isArray(route.matched) || route.matched.length === 0) {
return route;
}
return route.matched[0];
};
子页面代码(正常缓存写法即可)
<router-view v-slot="{ Component, route }">
<keep-alive>
<component :is="Component" :key="route.name" v-if="route.meta.keepAlive"></component>
</keep-alive>
<component :is="Component" :key="route.name" v-if="!route.meta.keepAlive"></component>
</router-view>
2. 优化缓存后页面一直不刷新问题(部分逻辑需要刷新)
例如:从菜单进入缓存列表页面需要刷新,但是从列表页面进入详情页后返回不需要刷新列表页
思路:
1、在路由中新增isBack字段用于判断是否需要刷新, 路由守卫出判断从那个页面进入的,不需要刷新改为true(例如详情),特殊情况也可以在地址中添加isRefresh参数控制(isRefresh==1需要刷新),实现同一个页面可根据不同的情况拼接isRefresh参数实现是否需要刷新缓存
2、不加入sessionStorage缓存会导致从详情切换到任意缓存列表页都不会请求数据,改进后只有返回跳转前的缓存页才不请求数据
路由守卫代码
router.beforeEach((to, from, next) => {
var prevRouter = sessionStorage.getItem("prevRouter");
if (from.meta.isDetail && !from.query.isRefresh && to.path == prevRouter) {
to.meta.isBack = true
} else {
to.meta.isBack = false
}
if (to.meta.keepAlive) {
sessionStorage.setItem("prevRouter", to.path);
}else if(!to.meta.isDetail){
sessionStorage.setItem("prevRouter", "");
}
next()
})
页面路由
export default [
{
path: "/setting",
name: "setting",
meta: {
transform: false,
},
children: [
{
path: "list",
name: "list",
meta: {
keepAlive: true
},
component: () => import("@/pages/app-settings/jiuchuang/notice-examine.vue")
},
{
path: "detail",
name: "detail",
meta: {
isDetail: true
},
component: () => import("pages/app-settings/components/notice/notice-detail.vue")
},
],
component: () => import("pages/index.vue")
},
]
列表页面代码
import { onActivated } from "vue";
onActivated(() => {
// 调用时机为首次挂载以及每次从缓存中被重新插入时
if (!route.meta.isBack) {
//获取列表数据
loadata()
}
});