vue keepalive 实现原理
Vue KeepAlive 实现原理
Vue 的 KeepAlive 是一个内置组件,用于缓存不活动的组件实例,避免重复渲染和销毁,从而提升性能。其核心原理基于 Vue 的虚拟 DOM 和组件生命周期管理。
缓存机制
KeepAlive 通过维护一个缓存对象(cache)来存储被缓存的组件实例。当组件切换时,KeepAlive 会检查缓存中是否存在该组件的实例。如果存在,则直接复用;否则,创建新的实例并存入缓存。
缓存的键(key)通常由组件的 name 选项或组件自身的唯一标识生成。如果没有 name,则根据组件的 tag 和上下文生成唯一键。
生命周期钩子
KeepAlive 通过劫持组件的生命周期钩子实现缓存逻辑:
activated:当缓存的组件被激活(重新显示)时触发。deactivated:当缓存的组件失活(被隐藏)时触发。
这两个钩子允许开发者在组件被缓存或恢复时执行特定逻辑,例如数据刷新或事件监听。
虚拟 DOM 处理
KeepAlive 在渲染时通过 render 函数动态决定是否返回缓存的组件实例。其核心逻辑如下:
- 通过
slot获取默认插槽内容(即被包裹的组件)。 - 根据组件的
key检查缓存中是否存在匹配的实例。 - 如果存在,返回缓存的 VNode;否则,创建新的 VNode 并存入缓存。
LRU 缓存策略
默认情况下,KeepAlive 使用 LRU(最近最少使用)策略管理缓存。当缓存数量超过 max 属性设定的值时,最久未被访问的实例会被销毁。LRU 通过维护一个访问顺序的链表实现。
代码示例
以下是一个简化版的 KeepAlive 实现逻辑:
const KeepAlive = {
name: 'KeepAlive',
props: {
max: Number, // 最大缓存数
},
created() {
this.cache = new Map(); // 缓存组件实例
this.keys = new Set(); // 维护访问顺序
},
render() {
const slot = this.$slots.default;
const vnode = slot[0]; // 获取被包裹的组件 VNode
const key = vnode.key ?? `${vnode.tag}-${vnode.componentOptions.Ctor.cid}`;
if (this.cache.has(key)) {
vnode.componentInstance = this.cache.get(key).componentInstance;
this.keys.delete(key);
this.keys.add(key); // 更新访问顺序
} else {
this.cache.set(key, vnode);
this.keys.add(key);
if (this.max && this.keys.size > this.max) {
const oldestKey = this.keys.values().next().value;
this.cache.delete(oldestKey);
this.keys.delete(oldestKey);
}
}
return vnode;
},
};
使用场景
- 动态组件切换(如 Tab 标签页)。
- 路由视图缓存(如 Vue Router 的
<router-view v-slot="{ Component }"><keep-alive><component :is="Component" /></keep-alive></router-view>)。 - 需要保留组件状态(如表单输入、滚动位置)的场景。
注意事项
- 被缓存的组件必须具有唯一的
key,否则可能导致状态混乱。 - 频繁缓存大量组件可能增加内存占用,需合理设置
max。 - 缓存的组件不会触发
destroyed钩子,需通过deactivated清理资源。







