跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

什么是 Patch 过程?手把手带你阅读 Vue 源码中的属性比对逻辑

Patch 是 Vue 更新视图的核心机制,通过比对新旧 VNode 实现最小化 DOM 操作,关键在复用与按需更新;sameVnode 判定(tag、key、isComment、isAsyncPlaceholder 全等)决定是否复用节点;patchVnode 处理单节点属性与文本更新,Vue 3 的 patchFlag 进一步优化比对粒度。 Patch 过程是 Vue 更新视图的核心机制,它不重绘整个 DOM,而是通过比对新旧虚拟节点(VNode),精准找出差异,再执行最小化的真实 DOM 操作。关键不在“重写”,而在“复用”和“按需更新”——只要节点可复用(sameVnode 判定通过),就只更新变化的属性、文本或子结构。 Patch 的入口与触发时机 每次响应式数据变更后,组件会重新执行 render 函数生成新 VNode,接着调用 vm.__patch__(prevVnode, vnode) 启动更新流程。这个函数由 createPatchFunction 工厂函数生成,封装了节点操作能力(如 nodeOps)和模块钩子(如 class、style、事件监听器的更新逻辑)。 首次渲染时 oldVnode 是真实 DOM 元素;更新时则是上一次的 VNode。入口统一,但分支逻辑完全不同: oldVnode 是真实元素 → 走挂载路径:创建新节点、插入父容器、移除旧节点 oldVnode 是 VNode → 进入 diff 主干:先 sameVnode 判断,再 patchVnode 或 updateChildren sameVnode:复用的前提,不是“看起来像”,而是“能复用” 判断是否走精细化更新,第一关就是 sameVnode(old, new) 。它检查的不是内容,而是节点身份标识: 立即学习 “ 前端免费学习笔记(深入) ”; Vue-router参考手册 Vue-router参考手册下载 下载 标签名(tag)相同 是否为注释节点(isComment)一致 key 值完全相等( key 是强制复用的关键依据 ) 是否为异步占位符(isAsyncPlaceholder)一致 四个条件全满足,才认为“这是同一个节点”,允许复用其真实 DOM 元素(el)。否则直接卸载旧节点、挂载新节点——跳过所有比对,避免错误复用。 patchVnode:单节点的属性与文本更新逻辑 当 sameVnode 为 true,进入 patchVnode ,它负责该节点自身的更新,不含子节点递归(子节点交由 updateChildren 处理)。核心逻辑分三类: 文本节点快捷路径 :若新旧 vnode 都是纯文本(isText === true),直接设置
el.textContent = newVnode.text
,不走任何属性比对 非文本节点的属性更新 :遍历
newVnode.data
中的 key(如 class、style、on、attrs),逐个调用对应模块钩子(如 updateClass、updateStyle、updateDOMListeners)——这些钩子内部只更新变化的部分,比如 class 只 diff 新旧 classList,不全量 setAttribute 子节点处理策略 : 新旧都有 children → 进入 updateChildren 旧有 children、新无 → 清空 el.innerHTML 旧无 children、新有 → 直接调用 createElm 批量挂载 Vue 3 的 patchFlag:让属性比对更聪明 Vue 3 引入 patchFlag 字段,在编译阶段就标记节点哪些部分可能变化。例如:
PatchFlags.CLASS
:仅需比对 class,忽略 id、style 等静态属性
PatchFlags.PROPS
(带特定 props 名称):只检查绑定的那几个响应式 prop
PatchFlags.TEXT
:说明只有子文本会变,跳过所有子节点结构比对 这意味着 patchVnode 不再盲目遍历全部 data 字段,而是根据 flag 精准命中需要更新的字段,大幅减少无效 diff 开销。这也是为什么 Vue 3 在模板中写
:class
和
{{ msg }}
能自动获得优化,无需手动加 key 或拆分组件。

相关文章