虚拟元素节点VNode
什么是虚拟元素节点?
虚拟元素节点即对真实dom节点的描述。包含标签名、标签属性描述对象、子节点集合。
// example
{
tag:'div'
props:{
key:'uuid',//VNode唯一key,新旧VNode diff时有用
id:'div',//VNode id值
//...
}
}
virtual dom优势?
不用直接操作dom,虚拟DOM具有批处理和高效的Diff算法,可以减少重排与重绘,提高性能;virtual dom是javascript对象,具有跨平台优势;
virtual dom diff思路
- VNode变化类型:
REPLACE:当前节点节点替换。比较方式:同一位置新旧节点一一对比。结构:{type:0,node:newNode}。
REORDER:子节点集合中新增、删除的子节点。比较方式:子节点集合同级对比。结构:{type:1,moves:[{type:0——删除,index:该子节点在子节点集合中的下标},{type:1——新增,index:该子节点在子节点集合中的下标,item:newVNode}]}。
PROPS:当前节点属性变化。比较方式:同一位置新旧节点一一对比。结构:{type:2,props:[{修改propKey:undefined——删除该属性,propKey:newPropValue}]}。
TEXT:当前节点文本节点变化。比较方式:同一位置新旧节点一一对比。结构:{type:3,content:newText}。
-
新旧虚拟dom diff思路总结:由于跨级修改很少,可忽略不计,所以仅进行同级子节点集合对比。
注意:新旧虚拟dom diff对比时,采用递归方法,并且从上往下统计。- 对比结果存放patches[key]:key为virtual dom tree递归时节点所处的位置,便于在patch应用在actual dom tree时,能准确找到对应的节点。
- 先进行newVNodeList与oldVNodeList中同位置(同index)的VNode对比,统计VNode的props、text,VNode被替换(标签名或VNode唯一key不一致)的改变
- 再进行同级childVNodeList对比,统计子节点删除、新增情况。并且返回含oldVNodeList.length长度和newVNodeList中VNode/Text值的新数组。通过VNode唯一key进行对比统计。
对比结果patches,应用到真实dom
注意:将对比结果patches,应用到真实dom时,采用递归方法,并且从下往上应用。
- patch.type===0(替换节点):node.parentNode.replaceChild(newNode,oldNode)
- patch.type===1(删除、新增子节点): removeChild(removeNode)、cloneNode(true)、insertBefore(insertNode,beforeNode)
- patch.type===2(props变化):removeAttribute(prop)、setAttribute(prop)
- patch.type===3(text变化):elementNode.textContent、textNode.nodeValue
参考网站:
深度剖析:如何实现一个 Virtual DOM 算法:https://github.com/livoras/blog/issues/13
同级VNodeList第一次对比代码:https://github.com/livoras/list-diff/blob/master/lib/diff.js
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。