patch 算法:将虚拟 DOM 变成真实 DOM
1. 初始化 patch(container, vnode)
将 vnode 创建为真实 DOM,并插入到容器中。
2. 更新 update(vnode, newVnode)
对比新旧 vnode 的差异,以最小代价更新真实 DOM。
function createElement(vnode) {
let tag = vnode.tag // 目标元素
let attrs = vnode.attrs || {}
let children = vnode.children || []
if (!tag) return null
let elem = document.createElement(tag)
let attrName
for (attrName in attrs) {
if (attrs.hasOwnProperty(attrName)) {
elem.setAttribute(attrName, attrs[attrName])
}
}
children.forEach(childVnode => {
elem.appendChild(createElement(childVnode))
})
return elem
}
function updateChildren(vnode, newVnode) {
let children = vnode.children || []
let newChildren = newVnode.children || []
children.forEach((childrenVnode, index) => {
let newChildrenVnode = newChildren[index]
if (childrenVnode.tag === newChildrenVnode.tag) {
updateChildren(childrenVnode, newChildrenVnode)
} else {
replaceNode(childrenVnode, newChildrenVnode)
}
})
}
补充:上述是 patch / diff 的极简实现。真正的 Vue 源码里会处理:
- 节点
key:通过 key 在 map 中查找可复用节点;- 双端指针
oldStart/oldEnd/newStart/newEnd四向比较;- 节点的增删改:在合适的位置插入 / 移动 / 删除真实 DOM;
- 组件级别的 patch:递归处理组件实例、props 变化、生命周期触发等。
来源整理自:vue3js.cn 面试官系列



