<KeepAlive> 是 Vue 内置的组件缓存机制。当一个被包裹的动态组件切换离开时,它不会被销毁,而是被缓存起来;等再次切换回来时,直接复用缓存的组件实例,并恢复之前的状态。
缓存原理:不销毁,只隐藏
在没有 <KeepAlive> 的情况下,切换动态组件时,离开的组件会被完整卸载(unmounted),其 DOM 被移除,组件实例被销毁,内部的所有状态丢失。下次再切换回来,必须从头初始化。
而 <KeepAlive> 改变了这个流程:
- 第一次渲染:组件正常创建、挂载、触发
setup和onMounted。 - 切换离开时:
<KeepAlive>并不会调用unmount,而是将组件实例连同其关联的 DOM 节点移入一个内存缓存池。此时组件变为“非活跃”状态,但它的所有响应式数据、DOM 状态(如输入框内容、滚动位置)、定时器等都仍然存在。 - 再次切换回来时:直接从缓存池中取出之前的组件实例,重新插入到 DOM 树中,不重新执行
setup,也不重新创建组件。
这样做的本质是以空间换时间:消耗少量内存来避免重复的组件创建和销毁开销,适用于在多个视图间频繁切换但数据需要保留的场景。
activated 与 deactivated:缓存感知的生命周期
因为组件在缓存期间并没有被销毁,常规的 onMounted / onUnmounted 无法反映切换过程。Vue 专门提供了两个钩子来响应“活跃”与“非活跃”的切换:
onActivated(或选项式activated):当被缓存的组件重新激活时调用。可以在这里执行数据刷新、重新启动定时器等操作。onDeactivated(或选项式deactivated):当组件被缓存起来时调用。适合在这里清除定时器、暂停动画、保存临时的交互状态。
一个完整的生命周期调用顺序示例:
首次进入组件 → setup → onMounted → onActivated
切换到其他组件 → onDeactivated
切回当前组件 → onActivated (不会再次调用 onMounted)
注意:onActivated 和 onDeactivated 只在被 <KeepAlive> 包裹的组件中才会被触发。对于直接挂载或卸载的组件,这两个钩子不会被调用。
实用场景
- 表单草稿保留:用户在一个多步骤步骤表单的第 2 步填写了一半,不小心切到第 1 步查看又切回来,输入的内容还保持原样,不需要用户重新填写。
- 滚动位置保持:一个资讯列表,用户滚动到第 3 页,点进详情后再返回列表,滚动条依然在原来的位置。
- 频繁切换的 Tab 页面:后台管理系统常见的 Tab 标签页,每个标签下是独立的查询结果或图表,缓存后可避免每次切换都重新请求数据、重新渲染图表。
常用配置项
include/exclude:通过字符串、正则或数组来指定哪些组件需要被缓存,哪些不需要。例如:
<KeepAlive include="Home,About">
<component :is="currentView" />
</KeepAlive>
max:限制缓存池的最大数量。当缓存实例超过该数量时,最早且未被再次访问的组件实例会被销毁,避免内存无限增长。
注意事项
- 如果组件已经缓存并再次激活,
setup不会重复执行,因此不能依赖setup中的初始化逻辑来刷新数据,应该把刷新逻辑放在onActivated中。 - 组件内部的定时器或异步请求如果在
onDeactivated中没有被清理,可能会导致内存浪费甚至 bug,建议成对处理:
let timer
onActivated(() => {
timer = setInterval(() => { ... }, 1000)
})
onDeactivated(() => {
clearInterval(timer)
})
- 当组件被缓存时,其 DOM 仍在内存中,但不可见,如果组件依赖
nextTick去获取元素尺寸,记得在onActivated中重新获取。
小结
<KeepAlive> 的核心价值在于在组件切换时保留用户的操作状态和 UI 状态,避免因销毁重建带来的性能损耗和数据丢失。activated 和 deactivated 则是与这套缓存机制配套的生命周期钩子,让开发者可以精确控制组件“休眠”与“唤醒”时的行为。