我们知道HTML5文本中,我们是无法使用jsx的,例如,下面的定义就会出错:
let vdom = (
)
babel也提供了远程cdn支持,所以我们只需要在头部引用
就行了。
当引入这个js文件后,你会出现下面的一行出错。
,babel默认解析jsx会去引入React,我们这没有React,当然就会出错。我们使用指令 ,/** @jsx hyperScript **/,定义一个自己的jsx渲染器,其中hyperScript 表示方法名字。
于是,我们的代码成了下面这个样子
/** @jsx hyperScript **/
let vdom = (
)
function hyperScript(nodeName , attributes , ...args){
}//这个方法用来解析jsx
我们书写这个方法。在jsx中,我们认为每一个虚拟DOM其实就是一个json文件。例如
,就会等价于{ nodeName :"div" , attrbutes : { id : "box"} , children : [] }。下面我们的hyperScript就会长这样
function hyperScript(nodeName , attributes , ...args){
//返回虚拟DOM, 虚拟DOM结构,用[].concat(...args) 连接所有子节点,返回构建完成的JSON。
let children = args.length ? [].concat(...args) : [];}
书写玩这个方法后,打印出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代码, 懒人直接运行就行了。