该算法比较新旧两个节点的差异,在最大程度复用旧节点的基础上把旧节点更新为新节点。
该算法的策略和 React 的 tree diff 一样,只比较同级节点,并且不移动节点,应该说不需要移动节点,因为新节点已经是真实的节点,而不是虚拟的节点。
function diff(oldNode,newNode){
if(oldNode.isEqualNode(newNode)){
return;
}
if(oldNode.nodeName!==newNode.nodeName){
oldNode.parentNode.replaceChild(newNode,oldNode);
return;
}
if(newNode.nodeType === 3){
if(oldNode.nodeType === 3){
oldNode.nodeValue = newNode.nodeValue;
}else{
oldNode.parentNode.replaceChild(newNode,oldNode);
}
return;
}
if(oldNode.nodeType === 3){
if(newNode.nodeType === 3){
oldNode.nodeValue = newNode.nodeValue;
}else{
oldNode.parentNode.replaceChild(newNode,oldNode);
}
return;
}
let oldNodeAttr = Array.from(oldNode.attributes);
let newNodeAttr = Array.from(newNode.attributes);
let oldNodeAttrSameIndex = {};
let newNodeAttrSameIndex = {};
for(let i=0,len=oldNodeAttr.length;i<len;i++){
for(let n=0,length = newNodeAttr.length;n<length;n++){
if(oldNodeAttr[i].isEqualNode(newNodeAttr[n])){
oldNodeAttrSameIndex[i] = true;
newNodeAttrSameIndex[n] = true;
}
}
if(!oldNodeAttrSameIndex.hasOwnProperty(i)){
oldNode.removeAttribute(oldNodeAttr[i].nodeName);
}
}
for(let i=0,len=newNodeAttr.length;i<len;i++){
if(newNodeAttrSameIndex[i]!==true){
oldNode.setAttribute(newNodeAttr[i].nodeName,newNodeAttr[i].nodeValue);
}
}
let newChildNodeList = Array.from(newNode.childNodes);
let oldChildNodeList = Array.from(oldNode.childNodes);
let newNodeLength = newChildNodeList.length;
let oldNodeLength = oldChildNodeList.length;
if(oldNodeLength > newNodeLength){
for(let i=0;i<oldNodeLength;i++){
if(newChildNodeList[i]!==undefined){
diff(oldChildNodeList[i],newChildNodeList[i]);
}else{
oldNode.removeChild(oldChildNodeList[i]);
}
}
}else{
for(let i=0;i<newNodeLength;i++){
if(oldChildNodeList[i]!==undefined){
diff(oldChildNodeList[i],newChildNodeList[i]);
}else{
oldNode.appendChild(newChildNodeList[i]);
}
}
}
}