1. 配置组件名称
确保列表页组件设置了name选项,(组合式API额外配置):
TypeScript
<!-- vue2写法 -->
export default {
name: 'UserList' // 必须与 <keep-alive> 的 include 匹配
}
<!-- vue3写法 -->
defineOptions({
name: "UserList"
});
2. 路由配置
在路由配置中添加 meta 标识是否需要缓存:
TypeScript
{
path: "/userList",
name: "UserList",
component: () => import("@/views/user/list.vue"),
meta: {
title: "用户列表",
keepAlive: true // 自定义缓存标识
}
},
3. 动态缓存控制
在 App.vue 中使用 <keep-alive>
包裹路由视图,并动态判断缓存:
TypeScript
<!-- App.vue -->
<template>
<router-view v-slot="{ Component, route }">
<keep-alive :include="cachedViews">
<component
:is="Component"
:key="route.fullPath"
v-if="route.meta.keepAlive"
/>
</keep-alive>
<component
:is="Component"
:key="route.fullPath"
v-if="!route.meta.keepAlive"
/>
</router-view>
</template>
<script setup lang="ts">
import { ref, watch } from "vue";
import { useRoute } from "vue-router";
const cachedViews = ref([]);
const route = useRoute();
watch(
() => route.meta.keepAlive,
newVal => {
if (newVal && !cachedViews.value.includes(route.name)) {
cachedViews.value.push(route.name);
}
}
);
</script>
4. 生命周期钩子
在列表页组件中使用 activated 钩子(vue3 使用 onActivated ) 处理返回时的逻辑:
TypeScript
<div class="list_box" @scroll="handleScroll" ref="listRef">
<van-list
v-model:loading="loading"
:finished="finished"
finished-text="没有更多了"
@load="getList"
>
.......
</van-list>
</div>
const listRef = ref(null);
// 缓存分页和滚动位置
const cachedState = ref({
page: 1,
scrollTop: 0
});
// 滚动事件处理
const handleScroll = e => {
// 实时保存滚动位置
cachedState.value.scrollTop = e.target.scrollTop;
// console.log("cachedState.value.scrollTop", cachedState.value.scrollTop);
};
onActivated(async () => {
console.log("组件激活,执行激活时的操作", cachedState.value.page);
if (cachedState.value.page > 1) {
searchQuery.page = cachedState.value.page;
}
await nextTick();
// 恢复滚动位置
if (listRef.value) {
listRef.value.scrollTop = cachedState.value.scrollTop;
}
});
onDeactivated(() => {
// 保存当前状态
cachedState.value.page = searchQuery.page;
console.log("组件停用", cachedState.value.page);
});
6. 高级场景:条件缓存
TypeScript
// 在全局前置守卫中
router.beforeEach((to, from) => {
if (from.name?.toString().includes('Detail') && to.name === 'UserList') {
to.meta.keepAlive = true // 从详情页返回时缓存
} else if (to.name === 'ListPage') {
to.meta.keepAlive = false // 从其他页面进入时不缓存
}
})