You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
var_=require('./util')varpatch=require('./patch')varlistDiff=require('list-diff2')functiondiff(oldTree,newTree){varindex=0varpatches={}dfsWalk(oldTree,newTree,index,patches)returnpatches}functiondfsWalk(oldNode,newNode,index,patches){varcurrentPatch=[]// Node is removed.if(newNode===null){// Real DOM node will be removed when perform reordering, so has no needs to do anthings in here// TextNode content replacing}elseif(_.isString(oldNode)&&_.isString(newNode)){if(newNode!==oldNode){currentPatch.push({type: patch.TEXT,content: newNode})}// Nodes are the same, diff old node's props and children}elseif(oldNode.tagName===newNode.tagName&&oldNode.key===newNode.key){// Diff propsvarpropsPatches=diffProps(oldNode,newNode)if(propsPatches){currentPatch.push({type: patch.PROPS,props: propsPatches})}// Diff children. If the node has a `ignore` property, do not diff childrenif(!isIgnoreChildren(newNode)){diffChildren(oldNode.children,newNode.children,index,patches,currentPatch)}// Nodes are not the same, replace the old node with new node}else{currentPatch.push({type: patch.REPLACE,node: newNode})}if(currentPatch.length){patches[index]=currentPatch}}functiondiffChildren(oldChildren,newChildren,index,patches,currentPatch){vardiffs=listDiff(oldChildren,newChildren,'key')newChildren=diffs.childrenif(diffs.moves.length){varreorderPatch={type: patch.REORDER,moves: diffs.moves}currentPatch.push(reorderPatch)}varleftNode=nullvarcurrentNodeIndex=index_.each(oldChildren,function(child,i){varnewChild=newChildren[i]currentNodeIndex=(leftNode&&leftNode.count)
? currentNodeIndex+leftNode.count+1
: currentNodeIndex+1dfsWalk(child,newChild,currentNodeIndex,patches)leftNode=child})}functiondiffProps(oldNode,newNode){varcount=0varoldProps=oldNode.propsvarnewProps=newNode.propsvarkey,valuevarpropsPatches={}// Find out different propertiesfor(keyinoldProps){value=oldProps[key]if(newProps[key]!==value){count++propsPatches[key]=newProps[key]}}// Find out new propertyfor(keyinnewProps){value=newProps[key]if(!oldProps.hasOwnProperty(key)){count++propsPatches[key]=newProps[key]}}// If properties all are identicalif(count===0){returnnull}returnpropsPatches}functionisIgnoreChildren(node){return(node.props&&node.props.hasOwnProperty('ignore'))}module.exports=diff
3.差异应用到真正的DOM树
patch.js
var_=require('./util')varREPLACE=0varREORDER=1varPROPS=2varTEXT=3functionpatch(node,patches){varwalker={index: 0}dfsWalk(node,walker,patches)}functiondfsWalk(node,walker,patches){varcurrentPatches=patches[walker.index]varlen=node.childNodes
? node.childNodes.length
: 0for(vari=0;i<len;i++){varchild=node.childNodes[i]walker.index++dfsWalk(child,walker,patches)}if(currentPatches){applyPatches(node,currentPatches)}}functionapplyPatches(node,currentPatches){_.each(currentPatches,function(currentPatch){switch(currentPatch.type){caseREPLACE:
varnewNode=(typeofcurrentPatch.node==='string')
? document.createTextNode(currentPatch.node)
: currentPatch.node.render()node.parentNode.replaceChild(newNode,node)breakcaseREORDER:
reorderChildren(node,currentPatch.moves)breakcasePROPS:
setProps(node,currentPatch.props)breakcaseTEXT:
if(node.textContent){node.textContent=currentPatch.content}else{// fuck ienode.nodeValue=currentPatch.content}breakdefault:
thrownewError('Unknown patch type '+currentPatch.type)}})}functionsetProps(node,props){for(varkeyinprops){if(props[key]===void666){node.removeAttribute(key)}else{varvalue=props[key]_.setAttr(node,key,value)}}}functionreorderChildren(node,moves){varstaticNodeList=_.toArray(node.childNodes)varmaps={}_.each(staticNodeList,function(node){if(node.nodeType===1){varkey=node.getAttribute('key')if(key){maps[key]=node}}})_.each(moves,function(move){varindex=move.indexif(move.type===0){// remove itemif(staticNodeList[index]===node.childNodes[index]){// maybe have been removed for insertingnode.removeChild(node.childNodes[index])}staticNodeList.splice(index,1)}elseif(move.type===1){// insert itemvarinsertNode=maps[move.item.key]
? maps[move.item.key].cloneNode(true)// reuse old item
: (typeofmove.item==='object')
? move.item.render()
: document.createTextNode(move.item)staticNodeList.splice(index,0,insertNode)node.insertBefore(insertNode,node.childNodes[index]||null)}})}patch.REPLACE=REPLACEpatch.REORDER=REORDERpatch.PROPS=PROPSpatch.TEXT=TEXTmodule.exports=patch
The text was updated successfully, but these errors were encountered:
对一个virtual dom实现的代码做的整理,原文见:livoras/blog#13
1.模拟dom树
element.js
使用:
var ul = el('ul', {id: 'list'}, [
el('li', {class: 'item'}, ['Item 1']),
el('li', {class: 'item'}, ['Item 2']),
el('li', {class: 'item'}, ['Item 3'])
])
var ulRoot = ul.render()
document.body.appendChild(ulRoot)
生成的dom结果如下:
`
虚拟dom树差异比对
每一层进行对比:复杂度O(n)
diff.js
3.差异应用到真正的DOM树
patch.js
The text was updated successfully, but these errors were encountered: