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文件后,你会出现下面的一行出错。
,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) )
是不是发现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>
还没有评论,来说两句吧...