Diff的目的是减少DOM操作的性能开销
简单diff:
if (Array.isArray(n1.children)) {//如果旧节点点是数组要进行diffconst oldChildren = n1.childrenconst newChildren = n2.childrenconst oldLen = oldChildren.lengthconst newLen = newChildren.lengthconst 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:
//如果旧节点点是数组要进行diffconst oldChildren = n1.childrenconst newChildren = n2.children//有key的比较let lastIndex = 0//循环新节点for (let i = 0; i < newChildren.length; i++) {let newVNode = newChildren[i]//判断是否能找到相同keylet find = false//循环旧节点for (let j = 0; j < oldChildren.length; j++) {let oldVNode = oldChildren[j]//如果两节点的key相同if (newVNode.key === oldVNode.key) {find = truepatch(oldVNode, newVNode, el)//如果j小于lastIndex则需要交换位置if (j < lastIndex) {//交换位置就是将el放置到新子节点的上一个节点el后面const prevVNode = newChildren[i - 1]if (prevVNode) {const anchor = prevVNode.el.nextSiblinginsert(oldVNode.el, el, anchor)}} else {//否则lastIndex=jlastIndex = j}break}}//如果新字节点不能找到相同的keyif (find === false) {//执行添加操作//然后将newVNode的el放置在上一节点的el后const prevVNode = newChildren[i - 1]let anchor = nullif (prevVNode) {anchor = prevVNode.el.nextSibling} else {anchor = el.firstChild}patch(null, newVNode, el, anchor)}}
