React JSX语法解析过程和原理

327 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

项目中的用法

ReactDOM.render(
    <div>
        <h1>这是标题</h1>
            今天你吃了吗???
        <div className="gren" style={{ color: 'green' }}>
            我应该吃了<br />
            还是没吃
        </div>
    </div>,
    document.getElementById('root')
);

1.通过 babel-preset 将JSX语法糖转义后:

React.createElement("div", {
  className: "myBox",
  style: {
    color: 'red',
    "font-size": '14px'
  }
}, /*#__PURE__*/React.createElement("h1", null, "\u8FD9\u662F\u6807\u9898"), "\u4ECA\u5929\u4F60\u5403\u4E86\u5417\uFF1F\uFF1F\uFF1F", /*#__PURE__*/React.createElement("div", {
  className: "gren",
  style: {
    color: 'green'
  }
}, "\u6211\u5E94\u8BE5\u5403\u4E86", /*#__PURE__*/React.createElement("br", null), "\u8FD8\u662F\u6CA1\u5403"))

在这里插入图片描述

2.React.createElement 将babel转义后的代码 生成虚拟的DOM对象

在这里插入图片描述

function createElement(type, props, ...childrens) {
    let ref, key;
    if (props && props.hasOwnProperty('key')) {
        key = props.key;
        delete (props.key);
    }
    if (props && props.hasOwnProperty('ref')) {
        ref = props.ref;
        delete (props.ref);
    }
    return {
        type,
        props: {
            ...props,
            children: childrens.length <= 1 ? (childrens[0] || '') : childrens,
        },
        key,
        ref
    };;
}

3.React.reder()执行 将虚拟DOM元素渲染到真实容器DOM中显示

function render(objJSX, container, callback) {
    let { type, props, children } = objJSX,
        element = document.createElement(type);
    // 处理props中的属性
    if (props) {
        let keys = Object.keys(props);
        for (let i in keys) {

            let attr = keys[i],
                value = props[attr];
            switch (attr) {
                case "className":
                    // 处理 className ,直接将className替换为class即可
                    element.setAttribute('class', value);
                    break;
                case "style":
                    // 处理style 将style中的每一项赋值到DOM元素上
                    Object.keys(value).forEach(item => {
                        element.style[item] = value[item];
                    })
                    break;
                case "children":
                    // 如果children 不是数组,将它变成数组,方便下边统一处理
                    if (!Array.isArray(value)) {
                        value = [value]
                    }

                    value.forEach(item => {
                        // 遍历数组每一项 如果当前项为字符串 创建一个文本节点 追加到DOM元素后边
                        if (typeof item === 'string') {
                            let text = document.createTextNode(item)
                            element.appendChild(text)
                        } else {
                            // 不是字符串类型,递归调用render解析
                            render(item, element)
                        }
                    })
                    break;
                default:
                    // 除以上特殊属性外 将JSX元素上的自定义属性值也放到DOM元素上
                    element.setAttribute(attr, props[attr])
            }
        }
    }
    // 将dom添加到父容器中
    container.appendChild(element);
    console.log("container——>", container);
    // 执行回调函数
    if (callback && typeof callback === 'function') callback()
}

在这里插入图片描述