简单实现react中虚拟DOM渲染

/**
 * @method createElement
 * @param type {string}
 * @param props {Object}
 * @param children {string}
 */
let createElement = (type, props, ...children) => {

    props = props || {};
    let obj = {
        type: null,
        props: {
            children: children.length <= 1 ? (children[0] || '') : children
        },
        key: null,
        ref: null,
    };
    obj = {...obj, type, props: {...props, children}};
    // eslint-disable-next-line no-unused-expressions
    'key' in obj.props ? (obj.key = obj.props.key, obj.props.key = undefined) : null;
    // eslint-disable-next-line no-unused-expressions
    'ref' in obj.props ? (obj.ref = obj.props.ref, obj.props.ref = undefined) : null;
    return obj;
};

/**
 * @method render
 * @param obj {Object}
 * @param container {elementNode}
 * @param callback {function}
 */
let render = (obj, container, callback) => {

    let {type, props} = obj || {},
        newElement = document.createElement(type);

    for (const attr in props) {

        if (!props.hasOwnProperty(attr)) break; // 不是私有的直接结束遍历
        if (!props[attr]) continue; // 如果当前属性没有值,直接不处理即可
        let value = props[attr];

        // className
        if (attr === 'className') {
            newElement.setAttribute('class', value);
            continue
        }

        // style
        if (attr === 'style') {
            // 如果style为空支付串,不处理
            if (value === '') continue;
            for (const styleKey in value) {
                if (value.hasOwnProperty(styleKey)) {
                    newElement['style'][styleKey] = value[styleKey];
                }
            }
            continue
        }

        // children
        if (attr === 'children') {

            // 先将其转换为数组,后期直接操作数组即可
            // eslint-disable-next-line no-unused-expressions
            !(value instanceof Array) ? value = [value] : null;
            value.forEach((item, index) => {
               if (typeof item === "string") {
                   let text = document.createTextNode(item);
                   newElement.appendChild(text)

               } else {
                   render(item, newElement);
               }
            });
            continue
        }
        newElement.setAttribute(attr, value);   // 基于setAttribute设置的属性,可以变现在HTML的结构上
    }

    container.appendChild(newElement);
    callback && callback();
};

let elementNode = createElement(
    'div',
    {id: 'container', ref: 'main', key: new Date()},
    createElement(
        'hr'
    ),
    createElement(
        'div',
        {id: 'header'},
        '头部'
    ),
    createElement(
        'hr'
    ),
    createElement(
        'div',
        {id: 'main'},
        '主体内容'
    ),
    createElement(
        'hr'
    ),
    createElement(
        'div',
        {id: 'footer'},
        '脚注'
    ),
);

// eslint-disable-next-line no-undef
render(elementNode, root, _ => console.log('ok'))

原文地址:https://www.cnblogs.com/korea/p/12017819.html