vue.js 的 patch 函数通过“节点类型 + key”双重判断识别相同类型节点,满足基础类型一致、key 相等(若有)、非异步/抽象节点三条件后复用并细粒度更新属性、子节点及组件实例。

Vue.js 的 patch 函数在更新 DOM 时,通过“节点类型 + key”双重判断来识别是否为“相同类型节点”,进而决定复用还是替换。核心逻辑不是简单比对标签名,而是结合虚拟节点(VNode)的类型标识、key 值以及是否为静态/组件节点等综合判定。
相同类型节点的判定条件
两个 VNode 被认为是“相同类型”需同时满足:
-
基础类型一致:都是普通元素(
tag相同且非 undefined)、都是组件(componentOptions存在且构造函数一致)、或都是注释/文本节点; -
key 值相等(如果存在 key):有
key时必须严格相等(===),这是跨列表更新复用的关键;无key时仅靠类型和顺序隐式匹配(易导致复用错误); -
不是异步占位符或抽象节点:如
v-if分支切换产生的空节点、<keep-alive></keep-alive>包裹的缓存节点等,会跳过就地复用逻辑。
patch 过程中如何处理相同类型节点
当判定为相同类型节点后,patchVnode(Vue 2)或 patchElement(Vue 3)被调用,执行细粒度更新而非销毁重建:
-
属性/指令同步:遍历新旧 VNode 的
data,对比attrs、props、class、style等,只更新变化项(如style.color改变则仅设 CSS 属性,不重写整个 style); - 子节点差异化更新:对子 VNode 列表执行双端 diff(Vue 2)或更精细的索引映射(Vue 3),移动、复用、更新或卸载子节点,避免全量重绘;
-
组件实例复用:若为组件节点且构造函数未变,保留原有实例,仅触发
beforeUpdate→updated钩子,并更新响应式 props 和 slots; -
文本节点快捷路径:纯文本节点直接更新
textContent,不走 DOM 属性 diff 流程。
常见误判场景与规避方式
看似相同的节点可能因细节差异被判定为“不同类型”,导致意外重建:
-
组件 name 或构造函数不一致:动态组件
:is="comp"中comp引用变更(如从 A.vue 切到 B.vue),即使 tag 名相同也视为不同组件; -
key 类型或值不匹配:数字
key="1"和字符串key="1"不等价;列表项 key 使用 index 会导致插入/删除时复用错乱; -
静态提升干扰:Vue 3 的编译器将静态节点标记为
isStatic: true,若新旧 VNode 静态标记不一致(如一个被提升一个未提升),可能绕过优化路径; -
函数式组件无实例:每次渲染生成新 VNode,即使 props 相同也无法复用 DOM,需依赖
key控制复用粒度。
调试建议:观察 patch 决策过程
可通过以下方式验证节点是否被正确识别为相同类型:
- 在自定义指令的
updated钩子中打印oldVnode === vnode,为true表明复用成功; - 使用 Vue Devtools 查看组件实例的
_uid是否变化,不变说明实例复用; - 给列表项添加唯一
key并开启 Devtools 的 “Highlight updates” 功能,观察 DOM 元素是否被移动而非新增/删除。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











