Diff的目的是减少DOM操作的性能开销
简单diff:
if (Array.isArray(n1.children)) {
//如果旧节点点是数组要进行diff
const oldChildren = n1.children
const newChildren = n2.children
const oldLen = oldChildren.length
const newLen = newChildren.length
const shortLen = Math.min(oldLen, newLen)
for (let i = 0; i < shortLen; i++) {
//先将length较短部分进行更新
patch(oldChildren[i], newChildren[i], el)
}
//如果旧字节点多则进行卸载
if (oldLen > newLen) {
for (let i = shortLen - 1; i < oldLen; i++) {
unmount(oldChildren[i])
}
}
//如果新的节点多则一一挂载
if (newLen > oldLen) {
for (let i = shortLen - 1; i < newLen; i++) {
patch(null, newChildren[i], el)
}
}
}
通过key进行diff:
//如果旧节点点是数组要进行diff
const oldChildren = n1.children
const newChildren = n2.children
//有key的比较
let lastIndex = 0
//循环新节点
for (let i = 0; i < newChildren.length; i++) {
let newVNode = newChildren[i]
//判断是否能找到相同key
let find = false
//循环旧节点
for (let j = 0; j < oldChildren.length; j++) {
let oldVNode = oldChildren[j]
//如果两节点的key相同
if (newVNode.key === oldVNode.key) {
find = true
patch(oldVNode, newVNode, el)
//如果j小于lastIndex则需要交换位置
if (j < lastIndex) {
//交换位置就是将el放置到新子节点的上一个节点el后面
const prevVNode = newChildren[i - 1]
if (prevVNode) {
const anchor = prevVNode.el.nextSibling
insert(oldVNode.el, el, anchor)
}
} else {
//否则lastIndex=j
lastIndex = j
}
break
}
}
//如果新字节点不能找到相同的key
if (find === false) {
//执行添加操作
//然后将newVNode的el放置在上一节点的el后
const prevVNode = newChildren[i - 1]
let anchor = null
if (prevVNode) {
anchor = prevVNode.el.nextSibling
} else {
anchor = el.firstChild
}
patch(null, newVNode, el, anchor)
}
}