需求1:
pageA
->
pageB
->
pageC
緩存pageB
:
從pageA
進入pageB
,刷新頁面并緩存頁面;
從pageC
返回pageB
,不刷新頁面
- 在 vuex(或其他存儲方案) 聲明兩個數(shù)組
{
state: () => ({
keepAliveViews: [],
notAliveViews: [],
}),
mutations: {
/**
* 記錄需要緩存的路由視圖
*/
saveKeepAliveViews(state, { keepAliveViews }) {
state.keepAliveViews = keepAliveViews;
},
/**
* 清除頁面緩存
*/
clearCacheView(state, { notAliveViews }) {
state.notAliveViews = notAliveViews;
},
},
}
- 在定義路由時,在
meta
中添加屬性keepAlive:true
{
name: "pageB",
path: "page-b",
component: () => import("***/pageB.vue"),
meta: {
keepAlive: true,
},
},
- 在適當位置遍歷路由表,記錄需要緩存的路由的組件名稱
// 記錄需緩存的路由/組件
const keepAliveViews = [];
router.getRoutes().forEach((routeItem) => {
if (routeItem?.meta?.keepAlive) {
// 組件name和路由name保持一致, 所以可以直接使用routeItem.name
// 也可以在 meta 中添加屬性 compName 來用,或其他方案
keepAliveViews.push(routeItem.name);
}
});
store.commit("saveKeepAliveViews", { keepAliveViews });
- 在路由根組件中
// template
<router-view v-slot="{ Component }">
<keep-alive :include="keepAliveViews" :exclude="notAliveViews">
<component :is="Component" />
</keep-alive>
</router-view>
// js
const keepAliveViews = computed(() => store.state.keepAliveViews);
const notAliveViews = computed(() => store.state.notAliveViews);
keep-alive
會緩存include
中存在的組件,會清除exclude
中的組件緩存;
- 手動清除組件緩存
/**
* 清除路由(組件/頁面)緩存
*/
export function clearCacheView(destroyCompNames) {
store.commit("clearCacheView", { notAliveViews: destroyCompNames });
// 清除緩存后,要重置數(shù)組為空,下次才能再次緩存
// 實際上不知道什么時候會完成緩存的清除,這里取500ms,一般滿足需求
setTimeout(() => {
store.commit("clearCacheView", { notAliveViews: [] });
}, 500);
}
{
name: "pageA",
path: "page-a",
component: () => import("***/pageA.vue"),
meta: {},
beforeEnter: () => {
clearCacheView(["pageB"]); // 這里的"pageB"是頁面pageB的組件名稱
},
返回pageA
時,手動清除pageB
的緩存;
需求2:
使用緩存頁面,大多數(shù)都是列表頁進入詳情頁,所以還需要考慮列表頁的滾動位置的問題.
即:pageC
返回pageB
時,pageB
要保持在離開時的位置
- 在 vuex(或其他存儲方案) 聲明一個數(shù)組
{
state() {
return {
keepAliveViewsScrollPostion: [],
};
},
mutations: {
// 設置緩存頁面滾動元素的位置
setkeepAliveViewsScrollPostion(state, { routeName, list }) {
const item = state.keepAliveViewsScrollPostion.find((t) => t.routeName === routeName);
if (!item) {
state.keepAliveViewsScrollPostion.push({ routeName, list });
} else {
item.list = list;
}
},
},
}
- 在定義路由時,在
meta
中添加屬性scrollEls
{
name: "pageB",
path: "page-b",
component: () => import("***/pageB.vue"),
meta: {
keepAlive: true,
scrollEls: [".scroll-list"], // 數(shù)組形式,可添加多個可滾動元素
},
},
- 在路由守衛(wèi)中
/**
* 全局前置守衛(wèi)
*/
router.beforeEach((to, from) => {
// 緩存頁面:記錄滾動位置
if (from.meta.scrollEls) {
const scrollObj: any = { routeName: from.name, list: [] };
from.meta.scrollEls.forEach((element) => {
const el = document.querySelector(element);
if (el) {
scrollObj.list.push({
el: element,
top: el.scrollTop,
});
}
});
store.commit("setkeepAliveViewsScrollPostion", scrollObj);
}
});
/**
* 全局后置鉤子
*/
router.afterEach((to, from) => {
// 緩存頁面:滾動到指定位置
nextTick(() => {
if (to.meta.scrollEls) {
const item = store.state.keepAliveViewsScrollPostion.find((t) => t.routeName === to.name);
if (!item) return;
item.list.forEach((item2) => {
const el = document.querySelector(item2.el);
if (el) {
el.scrollTop = item2.top;
item2.top = 0;
}
});
// 使用后重置滾動位置為0
store.commit("setkeepAliveViewsScrollPostion", item);
}
});
});