patch 函数是 Vue 渲染器中的核心函数,它负责对比新旧虚拟节点(VNode),并根据差异对实际 DOM 进行更新。这个过程涵盖了组件、元素、文本等不同类型节点的挂载、更新和卸载。
1 主要功能概括
1.1 比较节点类型
检查两个节点是否相同,如果不相同,则卸载旧节点并挂载新节点。
1.2 节点更新
节点 | 操作 |
---|---|
文本和注释节点 | 直接更新其内容 |
静态节点 | 对静态内容进行高效的插入和更新 |
Fragment(片段) | 特别处理 Fragment 类型,它允许一组子节点没有单一根节点 |
元素节点 | 更新元素的属性、事件监听器等 |
组件节点 | 处理组件的挂载、更新和卸载 |
Teleport | 特殊处理 Teleport 组件的插入和移动 |
Suspense | 处理异步组件的加载状态 |
优化处理 | 通过跳过某些静态节点的比较,以及利用编译时的提示(如 patch flags)来优化更新过程 |
指令和引用(Refs)的处理 | 更新或卸载时,处理相关的 Vue 指令和引用 |
递归子节点 | 对子节点递归执行相同的处理逻辑,确保整个虚拟 DOM 树正确、高效地更新 |
2. 源码解析
const patch: PatchFn = (
n1, //旧的虚拟节点
n2, //新的虚拟节点
container, //DOM 容器,在这个容器内进行渲染或更新
anchor = null, //锚点,用于定位新增节点的具体位置
parentComponent = null, //父组件的实例,用于上下文的传递和触发生命周期
parentSuspense = null, //用于 Vue 的 Suspense 功能,处理异步组件的加载状态
namespace = undefined, //命名空间,用于处理特定的 XML 命名空间或 SVG
slotScopeIds = null, //插槽作用域的 IDs,用于作用域插槽的内容
//表示是否进行了优化。如果为真,表示 n2 的子节点已经被静态优化了,不需要进行深度比较
optimized = __DEV__ && isHmrUpdating ? false : !!n2.dynamicChildren,
) => {
//节点相同的快速退出: 如果新旧节点相同 (n1 === n2),则无需进行任何操作。
if (n1 === n2) {
return
}
//类型不同时卸载旧节点:如果新旧节点类型不同 (!isSameVNodeType(n1, n2)),则获取旧节点的下一个兄弟节点作为锚点,并卸载旧节点。
if