test.html:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> fictitious dom</title>
</head> <body> <div id="root"></div> </body> </html> <script
type="text/javascript" src="diff.js"></script> <script type="text/javascript"
src="patch.js"></script> <script type="text/javascript"> // fictitious dom Class of class
Element{ constructor(type, props, children){ this.type = type; this.props =
props; this.children = children; } } // Return to virtual node function createElement(type,
props, children){ return new Element(type, props, children) } // set a property function
setAttr(node, key, value){ switch(key){ case 'value': //node It's an input box
if(node.tagName.toUpperCase() === 'INPUT' || node.tagName.toUpperCase() ===
"TEXTAREA"){ node.value = value; }else{ node.setAttribute(key, value); } break;
case 'style': node.style.cssText = value; break; default:
node.setAttribute(key, value) break; } } // Insert to page function renderDom(el,
target){ target.appendChild(el) } // Turn to node dom function render(eleObj){ let el =
document.createElement(eleObj.type); for(let key in eleObj.props){ // How to set properties
setAttr(el, key, eleObj.props[key]) } // There are child nodes eleObj.children.forEach(child => {
child = (child instanceof Element) ? render(child) :
document.createTextNode(child); el.appendChild(child) }) return el }
//----------------------------------------- // fictitious dom let vertualDom =
createElement('ul',{class:'list'},[ createElement('li',{class: 'item'}, ['a']),
createElement('li',{class: 'item'}, ['b']) ]) let vertualDom1 =
createElement('ul',{class:'list11'},[ createElement('li',{class: 'item'},
['a']), createElement('p',{class: 'item11'}, ['b1']) ]) // Will be virtual dom Turn it into reality dom Render to page
let el = render(vertualDom) renderDom(el, document.getElementById('root'))
// Modified patch let patches = diff(vertualDom, vertualDom1) console.log(patches)
// Update view again patch(el, patches) </script>
difff.js:
const ATTRS = 'ATTRS'; const TEXT = 'TEXT'; const REMOVE = 'REMOVE'; const
REPLACE = 'REPLACE'; let Index = 0; function diff(oldTree, newTree){ let
patches = {}; // patch let index = 0; // Node to start comparison // Recursive tree The results of the comparison are put into the patch package walk(oldTree,
newTree, index, patches) return patches; } // Attribute comparison function diffAttr(oldAttrs,
newAttrs){ let patch = {} // Comparison of new and old attributes for(let key in oldAttrs){ if(oldAttrs[key]
!== newAttrs[key]){ patch[key] = newAttrs[key] } } for(let key in newAttrs){
// The old node has no properties for the new node if(!oldAttrs.hasOwnProperty(key)){ patch[key] = newAttrs[key] } }
return patch; } function walk(oldNode, newNode, index, patches){ // Your own patch pack let
currentPatch = [] // Node deletion if(!newNode){ currentPatch.push({ type: REMOVE, index
}) }else if(isString(oldNode) && isString(newNode)){// character string // Text inconsistencies are updated
if(oldNode !== newNode){ currentPatch.push({ type: TEXT, text: newNode }) }
}else if(oldNode.type === newNode.type){// Same node type let attrs =
diffAttr(oldNode.props, newNode.props); // Determine whether the attribute has been modified
if(Object.keys(attrs).length > 0){ currentPatch.push({ type: ATTRS, attrs }) }
// Child node ergodic diffChildren(oldNode.children, newNode.children, patches); }else{
// The node is replaced currentPatch.push({ type: REPLACE, newNode }) } // There are patches
if(currentPatch.length > 0){ // Put the elements and patches in the big patch patches[index] = currentPatch
} } function diffChildren(oldChildren, newChildren, patches){
oldChildren.forEach((child, idx)=>{ // Index Global index walk(child, newChildren[idx],
++Index, patches) }) } function isString(node){ return
Object.prototype.toString.call(node) === "[object String]" }
patch.js:
let allPatches; let index = 0; // Index to be patched function patch(node, patches){
allPatches = patches patchWalk(node) } function patchWalk(node){ let
currentPatch = allPatches[index++] let childNodes = node.childNodes;
childNodes.forEach(child=>{ patchWalk(child) }) // There are patches if(currentPatch){
doPatch(node, currentPatch) } } // Patch corresponding nodes function doPatch(node, patches){
patches.forEach(item => { switch(item.type){ case 'ATTRS': for(let key in
item.attrs){ let val = item.attrs[key] if(val){ setAttr(node, key, val) }else{
node.removeAttribute(key) } } break; case 'TEXT': console.log(item.text)
node.textContent = item.text break; case 'REPLACE': let newNode = (item.newNode
instanceof Element) ? render(item.newNode) :
document.createTextNode(item.newNode); node.parentNode.replaceChild(newNode,
node) break; case 'REMOVE': break; default: break; } }) }
Technology
Daily Recommendation