babel对jsx的解析以及react虚拟dom树的加载转换

一、babel是提供对react jsx语法的支持

我们可以像以前一样脚本中引入babel的js包,实现浏览器对这种jsx的支持,默认的babel碰到jsx这种语法时候,会调用React里的API进行处理,下边示例中,我们没有引入React,则会报错。

这也是为什么 我们使用import导入react包的时候,名字必须为React。

2、稍微做一些改动,我们可以自定义对jsx的渲染,指令是:/** @jsx hyperScript **/,定义一个自己的jsx渲染器,其中hyperScript 表示方法名字。告诉babel在解析碰到jsx时候该如何做?

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

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

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

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

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

从下图中可以看出,引入script标签时候的type指定为babel,会在浏览器启动页面时候转换为内置的babel代码

jsx在解析后,参数如下图黑线标记的

3、显然react使用jsx写完的组件,最终被解析为了虚拟的json对象树,如下图:

我们只要把这个虚拟树渲染到真实的dom下就可以了,需要一个render函数,也就是ReactDOM.render函数的功能,这里我们自己定义一个,如下:

本质上就是将虚拟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;
        }

4、将返回的真实的dom对象,使用jquery放置到对应的div下即可

二、附上html源代码测试

https://github.com/longyangzz/react-jsx-virtualDom


<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />

    <script src="../build/babel.min.js"></script>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
  </head>
  <body>
    <div id="example"> 1234556 </div>
    <script type="text/babel">
      /** @jsx hyperScript **/
      const my = <div id="name">Hello, world!</div>
      // ReactDOM.render(
      //         my,
      //   document.getElementById('example')
      // );
      var realNode = render(my)

      //! 放到页面上的div下,作为虚拟dom的root节点
      var oDivs = document.getElementById("example");
      $("#example").html(realNode);

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

      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;
      }
    </script>
  </body>
</html>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值