KeepAlive

缓存组件实例,让组件切换后保留原来的状态

干什么用的?

<KeepAlive> 是 Vue 内置组件,用来缓存动态组件或路由组件。组件从页面上离开时不会被销毁,再次进入时可以复用原来的实例,因此表单内容、滚动位置和组件内部状态都能保留。

常见场景:

  • Tab 切换:切回 Tab 时保留筛选条件和输入内容
  • 列表与详情页:从详情返回列表时保留列表位置
  • 多个编辑页:在不同编辑页之间切换时保留草稿

它不是“让组件一直显示”,而是把组件从 DOM 中移除,同时把实例放入缓存。

基本用法

缓存动态组件

<KeepAlive>
  <component :is="activeTab" />
</KeepAlive>

也可以使用 includeexclude 精确控制哪些组件参与缓存:

<KeepAlive :include="['UserList', 'UserDetail']" :max="10">
  <component :is="activeComponent" />
</KeepAlive>

includeexclude 支持组件名字符串、逗号分隔字符串、正则表达式和数组。include 优先表示“只缓存匹配的组件”,exclude 表示“匹配的组件不缓存”。

与生命周期的关系

组件首次进入时,仍然会正常执行 createdmounted(Vue 2)或 onMounted(Vue 3)。被缓存后:

  • 离开当前视图:触发 deactivated / onDeactivated,组件实例不会销毁
  • 再次进入视图:触发 activated / onActivated,组件实例会被复用
  • 从缓存中真正移除:才会触发 beforeUnmountunmounted(Vue 3)或对应的 Vue 2 销毁钩子
<script setup>
import { onActivated, onDeactivated } from 'vue'

onActivated(() => {
  // 重新进入时刷新必要数据或恢复滚动位置
})

onDeactivated(() => {
  // 离开时暂停轮询、动画等资源
})
</script>

被缓存不等于所有资源都会自动暂停。定时器、轮询、WebSocket 和事件监听应在 onDeactivated 中暂停或解绑,并在 onActivated 中恢复。

配置参数

参数作用
include只缓存名称匹配的组件
exclude匹配名称的组件不缓存
max限制最大缓存实例数,超出后淘汰最久未使用的实例

max 与 LRU

KeepAlive 通常使用 LRU(Least Recently Used,最近最少使用)策略管理缓存:

  1. 命中缓存时,组件被标记为最近使用
  2. 新组件进入且缓存已满时,淘汰最久未使用的实例
  3. 被淘汰的实例会真正卸载,随后再次进入会重新创建

合理设置 max 可以避免缓存过多页面导致内存占用持续增长。

路由页面缓存

Vue Router 中通常把 RouterView 渲染出的组件包在 KeepAlive 内:

<RouterView v-slot="{ Component }">
  <KeepAlive :include="['UserList']">
    <component :is="Component" />
  </KeepAlive>
</RouterView>

如果使用路由元信息决定是否缓存,可以这样写:

<RouterView v-slot="{ Component, route }">
  <KeepAlive v-if="route.meta.keepAlive">
    <component :is="Component" />
  </KeepAlive>
  <component v-else :is="Component" />
</RouterView>

常见坑点

1.include 匹配的是组件名

匹配依据是组件的 name,不是路由的 name。使用 include 时要确认组件名与配置一致。Vue 2 中通常需要显式声明 name;Vue 3 <script setup> 可以使用 defineOptions({ name: 'UserList' }) 声明名称。

2. 参数变化不一定会重新创建组件

同一个路由组件仅是参数变化时,KeepAlive 可能继续复用实例。需要响应 route.paramsroute.query 的变化,必要时在 onActivated 中重新拉取数据。

3. 需要“刷新”时不能只依赖 KeepAlive

想强制重建组件,应改变组件的 key,或在业务层移除对应缓存后再进入。不要为了刷新而随意给整个页面树增加随机 key,否则会失去缓存收益。

4. 缓存状态与服务端数据不是一回事

KeepAlive 只缓存前端组件实例,不会自动保证数据最新。回到页面时是否请求接口,应根据数据时效性在 onActivated、路由守卫或状态管理层中明确处理。

总结

特性说明
作用缓存动态组件或路由组件实例
离开页面deactivated,不会立即销毁
再次进入activated,复用原实例
淘汰方式max 配合 LRU 策略
匹配依据组件的 name,不是路由 name
使用提醒管理轮询、监听器等资源,并处理数据刷新