在 Vue3 + TypeScript 项目中管理路由缓存,可以通过以下步骤实现:
<!-- App.vue -->
<template>
<router-view v-slot="{ Component }">
<keep-alive :include="cachedViews">
<component :is="Component" :key="$route.fullPath" />
</keep-alive>
</router-view>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const cachedViews = ref<string[]>([])
</script>
// types/vue-router.d.ts
import 'vue-router'
declare module 'vue-router' {
interface RouteMeta {
/** 是否需要路由缓存 */
keepAlive?: boolean
/** 动态缓存标签(用于相同组件不同参数的场景) */
cacheKey?: string
}
}
// router.ts
import { createRouter, createWebHistory } from 'vue-router'
export default createRouter({
history: createWebHistory(),
routes: [
{
path: '/list',
name: 'ListPage',
component: () => import('@/views/ListPage.vue'),
meta: {
keepAlive: true, // 需要缓存
cacheKey: 'list' // 唯一缓存标识
}
},
{
path: '/detail/:id',
name: 'DetailPage',
component: () => import('@/views/DetailPage.vue'),
meta: {
keepAlive: false // 不需要缓存
}
}
]
})
<!-- ListPage.vue -->
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'ListPage', // 必须显式声明 name(与路由配置中的 name 一致)
// ...
})
</script>
// router.ts
router.beforeEach((to, from) => {
const cachedViews = useCachedViewsStore() // 假设使用 Pinia 管理状态
// 离开需要缓存的页面时添加缓存
if (from.meta.keepAlive && from.name) {
const cacheKey = from.meta.cacheKey || from.name
cachedViews.add(cacheKey)
}
// 进入页面时根据 meta 配置处理缓存
if (to.meta.keepAlive && to.name) {
const cacheKey = to.meta.cacheKey || to.name
if (!cachedViews.includes(cacheKey)) {
cachedViews.add(cacheKey)
}
}
})
<!-- 在需要控制缓存的组件内 -->
<script setup lang="ts">
import { useRouter } from 'vue-router'
import { useCachedViewsStore } from '@/stores/cachedViews'
const router = useRouter()
const cachedViews = useCachedViewsStore()
// 进入页面时添加缓存
onMounted(() => {
if (router.currentRoute.value.meta.keepAlive) {
const cacheKey = router.currentRoute.value.meta.cacheKey || router.currentRoute.value.name!.toString()
cachedViews.add(cacheKey)
}
})
// 离开页面时移除缓存
onBeforeUnmount(() => {
if (router.currentRoute.value.meta.autoRemoveCache) {
const cacheKey = router.currentRoute.value.meta.cacheKey || router.currentRoute.value.name!.toString()
cachedViews.remove(cacheKey)
}
})
</script>
// 动态路由配置
{
path: '/user/:id',
component: UserDetail,
meta: {
keepAlive: true,
cacheKey: (route) => `user_${route.params.id}` // 动态生成缓存标识
}
}
// 路由守卫中处理
router.beforeEach((to, from) => {
if (typeof to.meta.cacheKey === 'function') {
to.meta.cacheKey = to.meta.cacheKey(to)
}
})
<keep-alive :max="5"> <!-- 最多缓存 5 个实例 -->
<component :is="Component" :key="cacheKey" />
</keep-alive>
// 在组件中添加生命周期钩子
onActivated(() => {
console.log('组件被激活,可能来自缓存')
// 这里可以添加数据刷新逻辑
})
onDeactivated(() => {
console.log('组件被停用,进入缓存')
})
缓存策略:
内存管理:
// 定时清理过期缓存
setInterval(() => {
cachedViews.value = cachedViews.value.filter(key => {
return lastAccessedTime[key] > Date.now() - 30 * 60 * 1000 // 30分钟有效期
})
}, 5 * 60 * 1000)
性能优化:
<keep-alive :max="5" :exclude="/MobilePage/">
<!-- 排除移动端页面 -->
<component :is="Component" />
</keep-alive>
TypeScript 强化:
// 组件名称类型校验
type ValidCacheNames = 'ListPage' | 'UserPage' | 'ProductPage'
interface CustomRouteMeta extends RouteMeta {
keepAlive?: boolean
cacheKey?: ValidCacheNames | ((route: RouteLocationNormalized) => string)
}
通过以上方案,可以实现以下功能: