美文网首页
react基础4:jsx语法渲染流程

react基础4:jsx语法渲染流程

作者: 转移到CSDN名字丹丹的小跟班 | 来源:发表于2021-01-19 10:59 被阅读0次

    jsx语法的解析

    ReactDOM.render(
    <div className="box" style={{color: 'red'}}>dandan</div>,
    document.getElementById('root')
    )
    

    1.首先基于babel的语法解析模块(babel-preset-react)把jsx语法编译为react.creacteElement(....)结构

    <div className="box" style={{color: 'red'}}>dandan</div>
    //编译成以下结构:
    React.createElement("div", {
      id: "div",
      className: "box",
      style: {color: 'red'}
    }, "dandan")
    

    2.执行React.createElement()函数,创建了一个对象(虚拟DOM)

    // 根据传进来的值修改这个对象
    //    1. type直接赋值给type
    //    2. props中大部分属性都直接赋值给新对象props。
    //    3. 但有一些比较特殊,如果是ref,key等值,我们需要把在props里面的值提取出来,创建两个新的对象存储,对象键就为ref,key,并将props里面的值删除
    //    4.把传递进来的children作为新创建对象props中的一个属性(children为标签里的元素(可能是一个标签,文本或者更多的嵌套的标签))
    // 编写createElement方法
    // children有可能不止一个(如果有多个子元素就不止一个),也有可能一个没有
    {
      type: 'div'
      ref: null
      key: null
      props: {
        id: 'div',
        className: 'box',
        style: {color: 'red'}
      __proto__: Object.prototype
    }
    
    1. ReactDom.render() 将jsx语法最后生成的对象插入容器, 基于render方法把生成的对象动态创建为DOM元素,插入到指定容器里)

    自己创建的createElement()函数

    // children可能不止一个(如果有多个子元素就不止一个),也有可能一个没有,所以用...接取
    function createElement(type, props, ...childrens) {
        // props可能不会有值,当无值时为{}
        props = props || {}
        // 定义ref, key变量,用于赋值
        let ref, key
        if("key" in props) {
            key = props.key
        }else {
            props.key = undefined
        }
        if("ref" in props) {
            ref = props.ref
        }else {
            props.key = undefined
        }
        // 返回一个对象
        return {type, props: {...props, children: childrens.length <= 1 ? childrens[0] : childrens}}
    }
    

    编写render方法 (作用:将创建的对象生成dom元素最后插入到页面当中)

    function render(obj, container, callback) {
        // obj已经从createElement里得到
        // {
        //   type: 'div',
        //   props: {
        //     id: 'div',
        //     className: 'box',
        //     style: { color: 'red' },
        //     children: 'dandan'
        //   },
        //   ref: null,
        //   key: null
        // }
        
        // 首先结构赋值取出type, props
        let {type, props} = obj || {}
            //创建一个新元素
        let newElement = document.createElement(type)
        // 遍历props对象
        for(let attr in props) {
            // 检测是否为私有属性,如果不是则跳过此次循环
            if(!props.hasOwnProperty(attr)) continue
            // 检测该属性是否有值,如果没有则跳过此次循环
            if(!props[attr]) continue 
            // 取出属性值,将值赋值给元素
            let value = props[attr]
            // 一些属性需要单独处理
            // class
            if(attr === 'className') {
                newElement.setAttribute('class', value)
                continue
            }
            // style
            if(attr === 'style' && Object.prototype.toString.call(value) === '[object Object]') {
                for(let styKey in value) {
                    if(value.hasOwnProperty(styKey)) {
                        newElement.style[styKey] = value[styKey]
                    }
                }
                continue
            }
            // children可能为一个值(字符串或者jsx对象),也可能为一个数组(数组每一项可能是字符串,也可能是字符串)
            if(attr === 'children') {
              //如果不是数组,表示为一个值,则让他变成数组便于处理
                if(Object.prototype.toString.call(value) !== '[object Array]') {
                    value = [value]
                }
                value.forEach((item, index) => {
                    // 验证item类型,如果为对象则继续执行createElement方法,把创建的元素放到最开始的大盒子里
                    if(Object.prototype.toString.call(item) === '[object String]') {
                        let text = document.createTextNode(item)
                        newElement.appendChild(text)
                    }else {
                        render(item, newElement)
                    }
                })
                continue
            }
            newElement.setAttribute(attr, value)
        }
        container.appendChild(newElement)
        callback && callback()
    }
    

    调用方法

    render(createElement("div", {
      id: "div",
      className: "box",
      style: {color: 'red'}
    }, "dandan"), document.getElementById("root"), () => {
        console.log('ok')
    })
    

    相关文章

      网友评论

          本文标题:react基础4:jsx语法渲染流程

          本文链接:https://www.haomeiwen.com/subject/jrgtzktx.html