vue的patch策略以复用为核心,通过key+tag+类型三重校验决定组件复用与否;普通元素需tag相同且推荐设key;不可复用时直接替换;列表采用双端指针+key映射实现高效复用。

Vue 的 Patch 策略不是简单地替换节点,而是围绕“可复用性”构建的一套精细化对比逻辑——核心目标是尽可能保留已有 DOM 节点及其内部状态(比如 input 的光标位置、滚动条偏移、自定义组件实例),只做最小必要更新。
组件节点的复用判定:key + tag + 类型三重校验
当新旧 VNode 都是组件时,Vue 不仅比对 tag(组件名或函数引用),还严格检查:
- key 是否一致:这是复用的前提。没有 key 或 key 变化,即使组件类型相同,也会触发销毁重建
- 是否为同一构造函数:确保不是同名但不同实现的组件(例如两个都叫 MyButton 但来自不同模块)
- 是否满足 sameVnode 条件:包括 isComment、isAsyncPlaceholder、input type 一致性等细节
任意一项不满足,就走“卸载旧组件 → 创建新组件”流程;全部满足,则复用组件实例,仅触发 props 更新与生命周期钩子(如 updated 或 beforeUpdate)。
普通元素节点的复用:标签一致 + key 匹配
对于 div、span、button 等原生标签节点,复用条件更轻量:
- 必须 tag 相同(比如都是
div) - 推荐提供 key,否则仅靠顺序推断,易导致状态错乱(如列表中切换排序)
- data(属性、样式、事件)和 children 会递归 patch,而非整节点替换
例如:<div key="user-123" class="active">{{ name }}</div> 更新 name 后,DOM 元素本身被复用,仅 innerText 和 class 属性被更新。
不可复用场景:直接替换,不尝试 diff
以下情况 Vue 不进入深度比对,而是直接销毁旧节点、挂载新节点:
- 新旧节点 tag 完全不同(如
div→span) - 一个是组件,另一个是普通元素
- 一个是注释节点,另一个是元素节点
- key 存在且不相等(显式声明了不同 key)
这种“快路径退出”避免了无效计算,是 Patch 高效的关键设计之一。
子节点列表的双端复用策略
针对 v-for 渲染的动态列表,Vue 使用双端指针法提升复用效率:
- 先比对 oldStart ↔ newStart 和 oldEnd ↔ newEnd,快速复用未移动的头尾项
- 再尝试 oldStart ↔ newEnd(旧首移到新尾)和 oldEnd ↔ newStart(旧尾移到新首)
- 剩余未匹配节点,通过 key 映射表 查找可复用项,找不到则创建新节点
整个过程不依赖节点索引,只依赖 key,因此插入、删除、移动、反转等操作都能精准识别并复用已有节点。










