一、keep-alive 核心概念

作用
keep-alive 是 Vue3 的内置组件,用于缓存动态组件或路由组件实例,避免重复渲染带来的性能损耗。当组件被包裹时,会保留其状态(如数据、DOM 结构、滚动位置等),直到达到缓存上限或手动清理。

生命周期变化
被缓存的组件新增两个特殊生命周期:

  • onActivated:组件被激活时触发(首次加载或从缓存恢复)
  • onDeactivated:组件被缓存时触发
    常规的 unmounted 只会在组件被永久销毁时执行。

二、基础使用场景与示例

1. 动态组件缓存

场景:切换标签页时保留表单输入状态

<template>
  <button @click="currentTab = 'FormA'">表单A</button>
  <button @click="currentTab = 'FormB'">表单B</button>
  
  <keep-alive>
    <component :is="currentTab"></component>
  </keep-alive>
</template>

<script setup>
import { ref } from 'vue';
import FormA from './FormA.vue';
import FormB from './FormB.vue';

const currentTab = ref('FormA');
</script>

此时切换标签,输入框内容不会重置。


2. 路由级缓存

场景:SPA 应用中保留页面状态

<!-- App.vue -->
<template>
  <router-view v-slot="{ Component }">
    <keep-alive :include="['Home', 'Profile']">
      <component :is="Component" />
    </keep-alive>
  </router-view>
</template>
// router.js
{
  path: '/home',
  name: 'Home',
  component: () => import('./views/Home.vue'),
  meta: { keepAlive: true } // 可选元信息控制
}

通过 include 指定需缓存的组件名(需与组件 name 选项一致)。


三、高级配置技巧

1. 缓存策略控制

通过三个属性实现精准控制:

  • include:字符串/正则/数组,匹配需缓存的组件名
  • exclude:排除不需要缓存的组件
  • max:最大缓存数,超限时按 LRU 算法淘汰

示例

<keep-alive :max="5" include="['Dashboard', /^Chart/]">
  <router-view />
</keep-alive>

该配置会缓存:

  1. 名为 Dashboard 的组件
  2. 名称以 Chart 开头的组件
  3. 最多保留 5 个实例

2. 状态刷新管理

问题:缓存导致数据不更新
解决方案

<script setup>
import { onActivated } from 'vue';

onActivated(() => {
  fetchData(); // 每次激活时刷新数据
});
</script>

结合 onDeactivated 可清理定时器等副作用。


四、实战场景与解决方案

案例 1:列表页-详情页状态保留

需求:返回列表页时保留滚动位置和筛选条件

// router.js
const router = createRouter({
  scrollBehavior(to, from, savedPosition) {
    if (savedPosition) return savedPosition;
    if (from.meta.keepAlive) {
      return { top: from.meta.scrollTop || 0 };
    }
    return { top: 0 };
  }
});

在列表页组件中记录滚动位置:

<script setup>
import { onDeactivated } from 'vue';

onDeactivated(() => {
  route.meta.scrollTop = document.documentElement.scrollTop;
});
</script>

案例 2:解决定时器干扰

问题:组件缓存后定时器仍在运行
方案:在 deactivated 中清理

<script setup>
import { onActivated, onDeactivated } from 'vue';

let timer = null;

onActivated(() => {
  timer = setInterval(updateData, 5000);
});

onDeactivated(() => {
  clearInterval(timer);
});
</script>

五、原理深度解析

  1. 缓存机制

    • 内部维护 cache(Map 对象)存储组件实例
    • 使用 keys(Set 对象)记录访问顺序
    • 通过 pruneCacheEntry 淘汰旧实例
  2. DOM 处理
    激活时通过 move 方法将缓存的 DOM 重新插入文档流,而非重新渲染

  3. LRU 算法
    当达到 max 限制时,淘汰最久未访问的组件实例


六、最佳实践与注意事项

  1. 命名规范
    始终为可缓存组件设置 name 选项,确保 include/exclude 生效

  2. 内存监控
    避免无限制缓存,建议结合 max 和业务逻辑手动清理(可通过访问 __v_cache 实现)

  3. 组合式 API
    推荐使用 <script setup> 配合生命周期钩子,逻辑更清晰

  4. 调试技巧
    通过 Vue Devtools 的 "Components > KeepAlive" 面板查看缓存状态


完整示例项目结构

src/
├── components/
│   ├── FormA.vue
│   └── FormB.vue
├── views/
│   ├── Home.vue
│   └── Profile.vue
├── router.js
└── App.vue

通过上述配置,可实现多级路由缓存与状态管理。


本文综合了 Vue3 官方文档核心思想与最佳实践方案,如需更深入的实现细节,可参考 Vue 源码中的 runtime-core/src/components/KeepAlive.ts 模块。