Vue keep-alive 有什么作用?缓存策略和生命周期是什么?
简化版
keep-alive 用来缓存动态组件或路由组件实例,切换时不销毁组件,从而保留状态并减少重复渲染。它常用 include、exclude、max 控制缓存范围,并会触发 activated、deactivated 这类缓存相关生命周期。
详细版
典型用法:
<KeepAlive :max="10">
<component :is="currentView" />
</KeepAlive>
路由场景常和 router-view 配合:
<RouterView v-slot="{ Component }">
<KeepAlive>
<component :is="Component" />
</KeepAlive>
</RouterView>
keep-alive 适合列表页返回保留滚动位置、Tab 切换保留表单状态等场景。不适合缓存所有页面,否则内存会增长,还可能保留过期数据。
完整版教学
一、keep-alive 解决组件反复销毁重建的问题
默认情况下,动态组件或路由组件切走后会被卸载。
再次进入时,组件会重新创建,状态、滚动位置、未提交输入都可能丢失。
keep-alive 的作用是把组件实例缓存起来。
不使用 keep-alive:
列表页创建 -> 进入详情页销毁 -> 返回列表页重新创建
使用 keep-alive:
列表页创建 -> 进入详情页失活缓存 -> 返回列表页重新激活
如果列表页每次请求需要 500ms,用户来回 5 次就会明显感觉卡。 缓存后可以减少重复初始化,但也要承担内存占用和数据新鲜度问题。
二、它缓存的是组件实例,不只是 DOM
keep-alive 缓存的核心是组件实例。
组件的响应式状态、计算属性缓存、部分 DOM 状态都会保留下来。
所以返回页面时,不会像首次进入那样重新执行完整挂载流程。
<KeepAlive>
<UserList v-if="showList" />
</KeepAlive>
这意味着列表页中的 page=3、筛选条件、展开行状态都可能被保留。
但接口数据是否过期,需要业务自己判断。
缓存不是数据同步方案,它只是保留组件实例。
三、include、exclude、max 控制缓存边界
include 表示只缓存匹配的组件,exclude 表示排除匹配的组件,max 表示最多缓存多少个实例。
这些配置通常依赖组件的 name。
如果组件没有稳定 name,匹配可能失效。
<KeepAlive include="UserList,OrderList" :max="10">
<component :is="currentView" />
</KeepAlive>
| 配置 | 作用 | 常见用途 |
|---|---|---|
include | 只缓存命中的组件 | 只缓存列表页 |
exclude | 不缓存命中的组件 | 排除详情页、编辑页 |
max | 限制缓存数量 | 防止内存无限增长 |
如果 max=10,第 11 个组件进入缓存时,最久未使用的缓存实例会被移除。
这类似 LRU 思路,能避免缓存越堆越多。
四、activated 和 deactivated 是缓存场景关键生命周期
被 keep-alive 缓存的组件切走时,不会走普通卸载逻辑。
它会进入失活状态,触发 deactivated。
再次显示时触发 activated。
onActivated(() => {
console.log('从缓存中恢复');
});
onDeactivated(() => {
console.log('进入缓存');
});
这些钩子适合恢复滚动位置、刷新轻量数据、暂停定时器。
例如图表页面进入缓存时暂停轮询,恢复时再继续。
如果仍把所有清理都写在 unmounted,缓存切换时可能不会执行。
五、路由页面缓存要和 meta 配合设计
实际项目很少无脑缓存所有路由。
常见做法是在路由 meta 中声明是否缓存,再在布局组件里判断。
这样缓存策略集中在路由配置里,更容易维护。
{
path: '/users',
component: UserList,
meta: { keepAlive: true },
}
流程示意:
进入路由
-> 读取 route.meta.keepAlive
-> true 包进 KeepAlive
-> false 正常渲染
编辑页通常不缓存,因为缓存旧表单可能造成误提交。 列表页常缓存,因为用户从详情返回时希望保留筛选和页码。
六、缓存会带来内存和数据新鲜度成本
keep-alive 不是性能银弹。
缓存越多,内存占用越高;组件状态保留越久,数据越可能过期。
所以要配合 max、刷新策略和清理逻辑。
适合缓存:
列表页、Tab 内容、搜索结果页
谨慎缓存:
编辑页、支付页、权限敏感页、实时数据页
记忆钩子:keep-alive 让组件“下场休息”,不是“彻底退场”;回来走 activated,不是重新 mounted。
面试时补上这句,基本就能区分普通挂载生命周期和缓存生命周期。 真正工程里,缓存策略要和业务状态一起设计。
七、常见误区与追问
- 误区:keep-alive 会让组件永远不销毁。 当不匹配缓存条件、超过
max或父级销毁时,缓存实例仍可能被移除。 - 误区:keep-alive 只缓存 DOM。 它缓存的是组件实例,状态、计算缓存和部分 DOM 状态都会被保留。
- 误区:所有路由都应该缓存以提升性能。 缓存会占内存,也可能保留过期或敏感状态,必须按页面类型选择。
- 追问:为什么 activated 不等于 mounted?
mounted是首次挂载,activated是缓存组件重新激活,触发时机不同。 - 追问:include 为什么有时不生效? 常见原因是组件 name 不匹配、异步组件命名不稳定或路由组件包裹方式不对。
- 追问:列表页返回详情后如何保留筛选条件? 可以缓存列表页实例,也可以把筛选条件放路由 query 或 store,按业务选择。
八、加强记忆
这题抓住“缓存组件实例”这个核心。先讲默认切路由会销毁重建,keep-alive 让组件失活而不是卸载;再讲 include/exclude/max 控制范围;最后讲 activated/deactivated 和缓存成本,说明它适合列表页、Tab,不适合所有页面。