KeepAlive 的底层原理是 Vue 在虚拟 DOM 层拦截复用组件实例,通过 Map+Set 管理缓存与 LRU 淘汰,跳过 mount 直接复用 subTree,保留完整运行时状态,并依赖 key 决定实例复用而非仅 diff 优化。

KeepAlive 的底层原理不是“不销毁组件”,而是 Vue 在渲染层构建了一套带策略的实例存档系统。 它不操作真实 DOM,也不生成新节点,而是在虚拟 DOM(VNode)层面拦截、复用和调度组件实例,核心动作发生在 render 阶段与组件挂载流程之间。
缓存对象:Map + Set 组合管理实例与访问顺序
KeepAlive 内部维护两个关键结构:
-
cache:Map 对象,以组件 key(如
vnode.key或name + uid)为键,存储完整的 VNode 及其关联的组件实例(componentInstance) - keys:Set 对象,按访问时间顺序记录所有缓存 key,用于实现 LRU 淘汰逻辑
每次激活组件时,对应 key 会被移至 keys 末尾;当缓存超限(max 触发),则移除 keys 首个 key 对应的缓存项。
渲染拦截:跳过 mount,直接复用 subTree
KeepAlive 是抽象组件(abstract: true),自身不参与 DOM 渲染。它的 render 函数会:
立即学习“前端免费学习笔记(深入)”;
- 从插槽中提取第一个子 VNode
- 检查 name 是否匹配
include/exclude规则 - 若命中缓存,直接返回已缓存的 VNode,并将其
subTree(即已挂载的 DOM 树根节点)注入当前渲染上下文 - 若未命中,则正常创建实例、执行
setup和mounted,再存入 cache
整个过程绕过了 createApp → mount 流程,也跳过了 beforeUnmount 和 unmounted,但保留了 deactivated / activated 钩子调用。
状态保留:缓存的是实例,不是快照
KeepAlive 缓存的是组件的运行时实例对象,包含:
- 响应式数据(
data、ref、reactive等) - 计算属性与侦听器(
computed、watch) - DOM 节点引用(
vnode.elm)及滚动位置、输入框值等原生状态 - 定时器、事件监听器、异步请求 pending 状态
这意味着组件切换后,this.$el.scrollTop、表单内容、轮播索引等全部保持原样——不是靠手动保存恢复,而是 DOM 节点从未脱离文档流,浏览器自然维持其状态。
key 机制:决定是否复用,而非仅用于 diff
在 <routerview></routerview> 中配合使用时,:key 的作用远超 diff 优化:
- 相同
key→ 复用缓存实例(即使路由参数变化,如/user/1→/user/2) - 不同
key→ 触发旧实例deactivated,新建实例并缓存(如加route.params.id或scopeId)
因此,业务中常写成::key="route.path + '_' + route.params.id" 或 :key="route.fullPath",确保语义不同的页面不共用缓存。


















