。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> </style> </head> <body> <div id="root" class="tt"> <div title="tt1">hello1</div> <div title="tt2">hello2</div> <div title="tt3">hello3</div> <ul> <li>1</li> <li>2</li> <li>3</li> </ul> </div> <script> // 用内存去表述DOM // 将真实DOM转化为虚拟DOM // <div /> => {tag:'div'} 元素转化 // 文本节点 => {tag:undefined,value:'文本节点'} 文本节点转化 // <div title="1" class="c" /> => { tag:'div',data:{ title:'1',class:"c" } } 多属性转化 // <div><div /></div> => {tag:'div',children:[{ tag:'div' }]} // 用构造函数来 进行以上转换 // 这一次我们用class语法 class VNode { // 构造函数 constructor( tag,data,value,type ){ // tag:用来表述 标签 data:用来描述属性 value:用来描述文本 type:用来描述类型 this.tag = tag && tag.toLowerCase();//文本节点时 tagName是undefined this.data = data; this.value = value; this.type = type; this.children = []; } appendChild( vnode ){ this.children.push( vnode ); } } /** 利用递归 来遍历DOM元素 生成虚拟DOM 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 ] 属性节点(nodeType == 2) 是对象 _attrObj[ attrs[ i ].nodeName ] = attrs[ i ].nodeValue; } _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 vroot = getVNode ( root ); console.log(vroot); </script> </body> </html>
。