react的虚拟DOM转换成DOM过程

1:babel的支持

    我们知道HTML5文本中,我们是无法使用jsx的,例如,下面的定义就会出错:

   let vdom = (<div id="box">
<div>hello ,World!</div>
<span>你好吗</span>
</div>

)

    babel也提供了远程cdn支持,所以我们只需要在头部引用

    <script src="https://unpkg.com/[email protected]/babel.min.js"></script> 就行了。

2:vdom转换过程

    当引入这个js文件后,你会出现下面的一行出错。

react的虚拟DOM转换成DOM过程,babel默认解析jsx会去引入React,我们这没有React,当然就会出错。我们使用指令 ,/** @jsx hyperScript **/,定义一个自己的jsx渲染器,其中hyperScript 表示方法名字。

于是,我们的代码成了下面这个样子

/** @jsx hyperScript **/
let vdom = (<div id="box">
<div>hello ,World!</div>
<span>你好吗</span>
   </div>

 )

function hyperScript(nodeName , attributes , ...args){

}//这个方法用来解析jsx

我们书写这个方法。在jsx中,我们认为每一个虚拟DOM其实就是一个json文件。例如<div id="liuyang"></div>,就会等价于

{ nodeName :"div" , attrbutes : { id : "box"} , children : []  }。下面我们的hyperScript就会长这样

function hyperScript(nodeName , attributes , ...args){

//返回虚拟DOM, 虚拟DOM结构,用[].concat(...args) 连接所有子节点,返回构建完成的JSON。

let children =  args.length ? [].concat(...args) : [];
return {nodeName,attributes,children  }

}

书写玩这个方法后,打印出vdom的结构

console.log( vdom )

console.log( JSON.stringify( vdom , null , 2) )

react的虚拟DOM转换成DOM过程

是不是发现vdom解析后就是一个json数据。

剩下的就是编写一个render方法了。render接受一个vdom,返回一个真实的DOM。

function render( vnode ){
//如果是字符,直接创建文本返回
if(vnode.split){
return document.createTextNode( vnode )
}
//node是一个真实DOM
let node = document.createElement( vnode.nodeName );
//获取属性
let attrs = vnode.attrbutes || {} ;
//给这个node节点遍历加上属性
Object.keys( attrs ).forEach( item => node.setAttribute( item , attrs[item] ) );
//如果有子元素,递归处理子元素并且给属性赋值,没有就结束
( vnode.children || [] ).forEach( item => node.appendChild( render(item) ) );
//返回node 
return node;
}

这时,我们定义一个let dom =  render( vdom ); console.log( dom )

打印出dom,得到解析完成的真实DOM节点了。是不是发现Vdom也不是那么神奇。

最后,贴上完整html代码, 懒人直接运行就行了。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://unpkg.com/[email protected]/babel.min.js"></script>
<script type="text/babel">
/** @jsx hyperScript **/
let vdom = (<div id="liuyang">
<div>hello ,World!</div>
<span>你好吗</span>
</div>
)
function hyperScript(nodeName , attributes , ...args){
//返回虚拟DOM, 虚拟DOM结构?
let children =  args.length ? [].concat(...args) : [];
return {nodeName,attributes,children  }
}
console.log( JSON.stringify( vdom , null , 2) )
console.log( vdom )
//虚拟DOM映射成 DOM节点 
function render( vnode ){
//如果是文本,直接返回
if(vnode.split){
return document.createTextNode( vnode )
}
//是一个虚拟DOM
let node = document.createElement( vnode.nodeName );
//get属性
let attrs = vnode.attrbutes || {} ;
//给节点加上属性
Object.keys( attrs ).forEach( item => node.setAttribute( item , attrs[item] ) );
//递归处理子元素,children
( vnode.children || [] ).forEach( item => node.appendChild( render(item) ) );
//返回node 
return node;
}


let dom =render( vdom );


console.log( dom )
</script>
</head>
<body>
</body>
</html>