司素浏览器
61.24M · 2026-02-07
//APP.vue
<router-view v-slot="{ Component }">
<KeepAlive>
<component :is="Component"/>
</KeepAlive>
</router-view>
//router/index.js
const routes = [
{
path: '/',
component: () => import('@/views/home/index.vue'),
name: 'home',
meta: {
title: '首页',
keepAlive: true,//是否缓存
},
},
]
const router = createRouter({
history: createWebHashHistory(),
routes,
})
//APP.vue
<template>
<router-view v-slot="{ Component, route }">
<keep-alive>
<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>
const routes = [
{
path: '/',
component: () => import('@/views/home/index.vue'),
name: 'home',//这里和component组件文件的defineOptions({ name: 'home'})保持一致
meta: {
title: '首页',
keepAlive: true,//是否缓存
},
},
]
const router = createRouter({
history: createWebHashHistory(),
routes,
})
<template>
<router-view v-slot="{ Component, route }">
<keep-alive :include="appStore.cacheList">
<component :is="Component" :key="route.fullPath" />
</keep-alive>
</router-view>
</template>
<script setup>
import { useAppStore } from '@/store/app'
const router = useRouter()
const appStore = useAppStore()
// 初始化缓存列表:根据路由配置添加需要缓存的组件
onMounted(() => {
appStore.initCacheList(router)
})
</script>
<style scoped></style>
import { defineStore } from 'pinia'
/**
* 应用状态管理 Store
* 主要用于管理 keep-alive 缓存列表
*/
export const useAppStore = defineStore('app', {
state: () => ({
// 缓存列表,存储需要缓存的组件名称
// keep-alive 的 include 需要匹配组件的 name
cacheList: []
}),
getters: {
/**
* 获取缓存列表(只读)
*/
getCacheList: (state) => {
return [...state.cacheList]
},
/**
* 检查某个组件是否在缓存列表中
*/
isCached: (state) => {
return (componentName) => {
return state.cacheList.includes(componentName)
}
}
},
actions: {
/**
* 初始化缓存列表:根据路由配置添加需要缓存的组件
* @param {Object} router - Vue Router 实例
*/
initCacheList(router) {
if (!router) {
console.warn('initCacheList: router 参数不能为空')
return
}
router.getRoutes().forEach(route => {
if (route.meta?.keepAlive && route.name) {
// keep-alive 的 include 需要匹配组件的 name
// 这里使用路由 name,需要确保路由 name 和组件 defineOptions 中的 name 一致
const componentName = route.name
if (!this.cacheList.includes(componentName)) {
this.cacheList.push(componentName)
}
}
})
},
/**
* 添加组件到缓存列表
* @param {string} componentName - 组件名称
*/
addCache(componentName) {
if (!componentName) {
console.warn('addCache: componentName 参数不能为空')
return
}
if (!this.cacheList.includes(componentName)) {
this.cacheList.push(componentName)
console.log(`已添加 ${componentName} 到缓存列表`)
}
},
/**
* 从缓存列表中移除组件(临时取消缓存)
* @param {string} componentName - 组件名称
*/
removeCache(componentName) {
if (!componentName) {
console.warn('removeCache: componentName 参数不能为空')
return
}
const index = this.cacheList.indexOf(componentName)
if (index > -1) {
this.cacheList.splice(index, 1)
console.log(`已移除 ${componentName} 的缓存`)
} else {
console.warn(`未找到 ${componentName} 的缓存`)
}
},
/**
* 清空所有缓存
*/
clearAllCache() {
this.cacheList = []
},
/**
* 根据路由信息自动管理缓存
* 如果路由配置了 keepAlive 为 true,则自动添加到缓存列表
* @param {Object} route - 路由对象
*/
autoManageCache(route) {
if (!route) return
const componentName = route.name
if (route.meta?.keepAlive && componentName) {
if (!this.cacheList.includes(componentName)) {
this.addCache(componentName)
}
}
}
}
})
import { processRoutes } from '@/utils/route-helper';//自动为组件设置路由 name的辅助工具
const routes = [....];//如上
// 自动为所有路由组件设置 name(如果组件没有设置 name,则使用路由 name)
const processedRoutes = processRoutes(routes);
const router = createRouter({
history: createWebHashHistory(),
routes: processedRoutes,
})
export default router;
/**
* 路由辅助工具
* 自动为组件设置路由 name,避免每个页面都手动设置 defineOptions
*/
import { defineComponent, h, markRaw } from 'vue'
/**
* 包装路由组件,自动设置组件 name 为路由 name
* @param {Function|Object} component - 组件导入函数或组件对象
* @param {string} routeName - 路由名称
* @returns {Function|Object} 包装后的组件
*/
export function withRouteName(component, routeName) {
if (!routeName) {
return component
}
// 如果是异步组件(函数)
if (typeof component === 'function') {
return () => {
return component().then((module) => {
const comp = module.default || module
// 如果组件已经有 name,直接返回
if (comp.name) {
return module
}
// 使用 defineComponent 包装组件,设置 name
const wrappedComponent = defineComponent({
name: routeName,
setup(props, { slots, attrs }) {
// 渲染原组件
return () => h(comp, { ...props, ...attrs }, slots)
}
})
// 标记为原始对象,避免响应式
markRaw(wrappedComponent)
// 返回包装后的组件
// 注意:需要先展开 module 再覆盖 default,否则 module.default 会把 wrappedComponent 覆盖掉
return {
...module,
default: wrappedComponent,
}
})
}
}
// 如果是同步组件(对象)
if (typeof component === 'object' && component !== null) {
// 如果组件已经有 name,直接返回
if (component.name) {
return component
}
// 使用 defineComponent 包装组件,设置 name
const wrappedComponent = defineComponent({
name: routeName,
...component
})
markRaw(wrappedComponent)
return wrappedComponent
}
return component
}
/**
* 批量处理路由配置,自动为组件设置 name
* @param {Array} routes - 路由配置数组
* @returns {Array} 处理后的路由配置数组
*/
export function processRoutes(routes) {
return routes.map(route => {
// 如果有 name 和 component,则自动设置组件 name
if (route.name && route.component) {
route.component = withRouteName(route.component, route.name)
}
// 递归处理子路由
if (route.children && Array.isArray(route.children)) {
route.children = processRoutes(route.children)
}
return route
})
}