为什么要使用虚拟DOM?
所谓虚拟DOM就是将一个DOM节点用数据描述出来,即在内存中描述标签。这样做的目的就是提高性能,避免反复渲染页面导致页面卡顿。
怎样使真正DOM变成虚拟DOM?
给虚拟DOM提供构造函数,用class存储。
例如:
< div / > ——> { tag: ‘div’, type=1 }
文本节点 ——> { tag: undefined, type=3, value:‘文本节点’ }
< div title=“1” class=“c” / > ——> { tag: ‘div’, type=1, data:{ title:“1”, class:“c”} }
< div >< div >< /div >< /div > ——> { tag: ‘div’, type=1, children:[ { tag:“div” } ] }
可以创建一个vue项目,在控制台的Console面板中输入app._vnode查看vue的虚拟DOM结构。
案例
class VNode {
//tag 标签名 data 属性 value 文本值 type 是否文本(1是元素,3是文本)
constructor( tag, data, value, type ){ //elm
this.tag = tag && tag.toLowerCase(); // tag?tag.toLowerCase():tag
this.data = data;
this.value = value;
this.type = type;
this.children = [];
}
// 追加子元素
appendChild(vnode){
this.children.push( vnode );
}
}
//将真正的DOM 转为虚拟的DOM
/**
* 使用递归 来遍历 DOM元素,生成虚拟DOM
*
* Vue中的源码使用的是 栈结构, 使用栈存储 父元素来实现递归生成 (因为Vue里面是把元素转换为字符串处理)
**/
function getVNode( node ){
let nodeType = node.nodeType;
let _vnode = null;
if(nodeType === 1){
//元素
let nodeName = node.nodeName;
let attrs = node.attributes; //伪数组
let _attrObj = {}; //存储属性
for( let i=0; i < attrs.length; i++){ //attrs[i] 属性节点
_attrObj[ attrs[i].nodeName ] = attrs[i].nodeValue;
}
//标签名nodeName,属性 _attrObj,因为是元素节点,所以没有文本值
_vnode = new VNode(nodeName, _attrObj, undefined, nodeType); //创建第一个节点
// 考虑 node 的子元素
let childNodes = node.childNodes;
for(let i=0; i<childNodes.length; i++){
_vnode.appendChild( getVNode(childNodes[i]) ); //递归
}
}else if(nodeType === 3){
//文本节点
_vnode = new VNode(undefined,undefined,node.nodeValue,nodeType);
}
return _vnode;
}
let root = document.querySelector('#root');
let virtualNode = getVNode( root )
console.log( virtualNode );
使用虚拟DOM对数据做出修改,当所有的数据都修改完毕后,再调用虚拟DOM转为真正的DOM的功能,替换到页面上,实现页面数据驱动,在一定程度上提高了性能。