详细分析KeepAlive的基本知识并缓存路由(附Demo)
- 开源代码
- 2025-09-11 01:45:02

目录 前言1. 基本知识2. Demo2.1 基本2.2 拓展2.3 终极 3. 实战 前言
🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF
基本知识推荐阅读:KeepAlive知识点
从实战中学习,源自实战中vue路由的缓存设置
<router-view v-if="routerAlive"> <template #default="{ Component, route }"> <keep-alive :include="getCaches"> <component :is="Component" :key="route.fullPath" /> </keep-alive> </template> </router-view>截图如下:
1. 基本知识<KeepAlive> 内置组件,用于缓存动态组件或路由组件,以提高性能 可以保留组件的状态,避免重复渲染和生命周期钩子的重新调用
KeepAlive 作用
缓存组件,提高性能,避免组件反复销毁和创建保留组件的状态,例如表单填写内容、滚动位置等控制缓存,可以指定哪些组件需要被缓存,哪些不需要KeepAlive 适用场景
需要缓存的 多页面表单列表详情页切换 时,保留列表的滚动位置复杂组件切换时,避免重新渲染带来的性能开销 功能说明KeepAlive用于缓存组件,提高性能include指定要缓存的组件(支持字符串或数组)exclude指定不缓存的组件max限制最大缓存组件数量activated()组件被激活时触发deactivated()组件被缓存时触发include 和 exclude 可以通过 include 和 exclude 来决定哪些组件需要被缓存,哪些不需要
<keep-alive include="ComponentA"> <component :is="currentComponent"></component> </keep-alive>只有 ComponentA 会被缓存,而 ComponentB 不会
或者:
<keep-alive :include="['ComponentA', 'ComponentC']"> <component :is="currentComponent"></component> </keep-alive>只有 ComponentA 和 ComponentC 会被缓存 如果需要排除某个组件:
<keep-alive exclude="ComponentB"> <component :is="currentComponent"></component> </keep-alive>ComponentB 不会被缓存,而其他组件都会被缓存
max —— 设置缓存组件的最大数量 如果缓存的组件较多,可以设置 max 限制最多缓存多少个组件 只缓存最近的两个组件,超出的组件会被销毁
<keep-alive :max="2"> <component :is="currentComponent"></component> </keep-alive>KeepAlive 生命周期钩子 Vue 提供了两个专门用于 KeepAlive 组件的生命周期钩子: activated():组件被激活(切换到缓存中的组件时调用) deactivated():组件被缓存(切换到另一个组件时调用)
<script> export default { created() { console.log("组件创建"); }, activated() { console.log("组件被激活"); }, deactivated() { console.log("组件被缓存"); }, destroyed() { console.log("组件被销毁"); }, }; </script>运行效果:
组件首次渲染时,created() 会触发当组件切换回来时,activated() 会触发,而不会重新执行 created()切换到别的组件时,deactivated() 触发,而不会执行 destroyed()只有当缓存被清除时,才会执行 destroyed() 2. Demo 2.1 基本动态组件缓存
<template> <div> <button @click="currentComponent = 'ComponentA'">切换到A</button> <button @click="currentComponent = 'ComponentB'">切换到B</button> <keep-alive> <component :is="currentComponent"></component> </keep-alive> </div> </template> <script> import ComponentA from "./ComponentA.vue"; import ComponentB from "./ComponentB.vue"; export default { data() { return { currentComponent: "ComponentA", }; }, components: { ComponentA, ComponentB, }, }; </script>组件 A (ComponentA.vue):
<template> <div> <h3>组件 A</h3> <input v-model="text" placeholder="输入内容会被缓存" /> </div> </template> <script> export default { data() { return { text: "", }; }, created() { console.log("ComponentA 创建"); }, destroyed() { console.log("ComponentA 被销毁"); }, }; </script>组件 B (ComponentB.vue):
<template> <div> <h3>组件 B</h3> </div> </template> <script> export default { created() { console.log("ComponentB 创建"); }, destroyed() { console.log("ComponentB 被销毁"); }, }; </script>一个最明显的变化就是: 在 ComponentA 中输入一些文字,然后切换到 ComponentB,再切回来,发现输入内容还在(ComponentA 没有被销毁)
2.2 拓展KeepAlive 也可以与 Vue Router 结合,缓存路由组件 这样在 PageA 和 PageB 之间切换时,PageA 不会被销毁,而是会被缓存
<template> <div> <router-link to="/pageA">页面 A</router-link> <router-link to="/pageB">页面 B</router-link> <keep-alive> <router-view></router-view> </keep-alive> </div> </template>路由配置:
import { createRouter, createWebHistory } from "vue-router"; import PageA from "./PageA.vue"; import PageB from "./PageB.vue"; const routes = [ { path: "/pageA", component: PageA }, { path: "/pageB", component: PageB }, ]; const router = createRouter({ history: createWebHistory(), routes, }); export default router; 2.3 终极这也是实战中常用的一种方式,从实战中抽离出基本的Demo,以 Vue 3 + Vue Router 4 + Pinia
装依赖:npm install vue-router@4 pinia
main.ts(应用入口)
import { createApp } from 'vue' import { createPinia } from 'pinia' import { createRouter, createWebHistory } from 'vue-router' import App from './App.vue' import Home from './views/Home.vue' import About from './views/About.vue' import Profile from './views/Profile.vue' const pinia = createPinia() // 定义路由 const routes = [ { path: '/', component: Home, name: 'Home' }, { path: '/about', component: About, name: 'About' }, { path: '/profile', component: Profile, name: 'Profile' } ] const router = createRouter({ history: createWebHistory(), routes }) const app = createApp(App) app.use(pinia) app.use(router) app.mount('#app')store/tagsView.ts(Pinia 状态管理 - 维护缓存组件列表)
import { defineStore } from 'pinia' export const useTagsViewStore = defineStore('tagsView', { state: () => ({ cachedViews: new Set<string>() }), getters: { getCachedViews(): string[] { return Array.from(this.cachedViews) } }, actions: { addCachedView(name: string) { this.cachedViews.add(name) }, removeCachedView(name: string) { this.cachedViews.delete(name) }, clearCachedViews() { this.cachedViews.clear() } } })App.vue(KeepAlive 组件封装)
<script setup lang="ts"> import { computed, ref, provide, nextTick } from 'vue' import { useTagsViewStore } from './store/tagsView' import { RouterView } from 'vue-router' const tagsViewStore = useTagsViewStore() const getCaches = computed(() => tagsViewStore.getCachedViews) // 无感刷新功能 const routerAlive = ref(true) const reload = () => { routerAlive.value = false nextTick(() => (routerAlive.value = true)) } provide('reload', reload) </script> <template> <div> <router-view v-if="routerAlive"> <template #default="{ Component, route }"> <keep-alive :include="getCaches"> <component :is="Component" :key="route.fullPath" /> </keep-alive> </template> </router-view> </div> </template>views/Home.vue
<script setup lang="ts"> import { inject } from 'vue' const reload = inject('reload') as () => void </script> <template> <div> <h1>Home Page</h1> <button @click="reload">刷新当前组件</button> </div> </template>views/About.vue
<template> <div> <h1>About Page</h1> </div> </template>views/Profile.vue
<template> <div> <h1>Profile Page</h1> </div> </template>动态路由的常用操作
动态添加路由 在 router.ts 中可以动态添加路由: import router from './router' const newRoute = { path: '/new-page', component: () => import('@/views/NewPage.vue'), name: 'NewPage' } router.addRoute(newRoute)动态移除路由:router.removeRoute('NewPage')
监听路由变化
import { useRoute, useRouter } from 'vue-router' import { watch } from 'vue' const route = useRoute() const router = useRouter() watch(() => route.fullPath, (newPath) => { console.log('路由发生变化:', newPath) }) 3. 实战以ruoyi-vue-pro实战的Demo进行讲解,源码:芋道源码/ruoyi-vue-pro
具体KeepAlive,其文件在App.vue中
<router-view v-if="routerAlive"> <template #default="{ Component, route }"> <keep-alive :include="getCaches"> <component :is="Component" :key="route.fullPath" /> </keep-alive> </template> </router-view>通过组件的设置是否路由进行缓存,后续获取到这个路由信息时,对应判定是否该路由有缓存信息
const getCaches = computed((): string[] => { const caches = tagsViewStore.getCachedViews console.log('当前缓存的组件:', caches) // 打印缓存的组件名称 return caches }) const tagsView = computed(() => appStore.getTagsView) //region 无感刷新 const routerAlive = ref(true) // 无感刷新,防止出现页面闪烁白屏 const reload = () => { routerAlive.value = false nextTick(() => (routerAlive.value = true)) } // 为组件后代提供刷新方法 provide('reload', reload)对应的tagsView信息如下:
后续在tsx中进行引用
后续新增路由的时候,其路由地址 要和 defineOptions({ name: 'xxx' }) 对应一致
详细分析KeepAlive的基本知识并缓存路由(附Demo)由讯客互联开源代码栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“详细分析KeepAlive的基本知识并缓存路由(附Demo)”