重写React.createElement和render方法

/* 创建虚拟DOM对象的 */
export const createElement = function createElement(type, props, ...params) {
    console.log("my-creatElement");
    let virtualDOM = {
        $$typeof: Symbol("react.element"),
        props: {},
        type,
        ref: null
    };
    //处理ref
    if (props.hasOwnProperty("ref")) {
        virtualDOM.ref = props.ref;
        delete props.ref
    }
    //处理传递的属性
    if (props) { //如果它存在不是null
        virtualDOM.props = {
            ...props
        }
    }
    //处理传递的子节点
    if (params.length > 0) {
        virtualDOM.props.children = params.length === 1 ? params[0] : params;
        //判断第三个参数及以后的参数有几个 如果只有一个把第一给children,如果有多个就把params这个数组给children
    }
    return virtualDOM
};
/* 把虚拟DOM变为真实DOM */
export const render = function render(virtualDOM, container) {
    console.log("my-render");
    let { type, props, ref } = virtualDOM, { children } = props;
    delete props.children; //我们已经把children获取到赋值给了其他变量了,此时就可以props中移除它
    if (typeof type === "string") {
        //要创建的是html标签
        let elem = document.createElement(type);
        //@1 给元素设置属性
        Reflect.ownKeys(props).forEach(key => {
            //拿到所有的私有属性
            let value = props[key]; //属性名
            if (key === "className") {
                elem.setAttribute("class", value);
                return
            };
            if (key === "style") {
                //JSX语法要求sytle是一个对象,我们需要迭代对象中的每一项,分别给真实的DOM设置行内样式
                //value={color:"red",fontSize:"16px"...}
                Reflect.ownKeys(value).forEach(item => {
                    elem.style[item] = value[item]
                })
                return;
            }
            elem.setAttribute(key, value);
        });
        //@2 给元素设置子节点
        if (children) {
            //确保不论几个节点,children都是一个数组
            children = !Array.isArray(children) ? [children] : children;
            children.forEach(child => {
                //如果其中的一个子节点是一个文本节点,直接把其放入elem容器中
                if (typeof child === "string") {
                    let textNode = document.createTextNode(child); //创建一个文本节点
                    elem.appendChild(textNode)
                    return
                }

                //如果是元素子节点(也就是一个新的虚拟DOM),需要基于递归,重新调用render方法,是不过容器是elem
                render(child, elem)
            })
        }
        //@3 处理ref的属性值
        if (ref) {
            if (typeof ref === "string") {
                //假设:this->实例
                this.refs[ref] = elem
            }
            if (typeof ref === "function") {
                ref.call(this, elem)
            }
            if (ref.current) {
                ref.current = elem
            }
        }
        container.appendChild(elem);
        return
    }

    /* 调用的是组件,我们还需要区分函数组件和类组件
    @1 如果是函数组件
        + 把其作为普通函数执行
        + 把props(包含children)传递给函数[对象是冻结的]
        + 接受函数的返回值[virtualDOM],再进行渲染
    @2  如果是类组件
        + 把其作为构造函数执行,创建一个实例
        + .....
     */


}
import React from 'react';
import ReactDOM from 'react-dom';
import { createElement, render } from './renderJSX'

// import Tc from './test'
// // let Tc = require("./test")
// console.log(Tc);

render(
  createElement(
    "div",
    { className: "box" },
    createElement(
      "h2",
      { className: "title", style: { color: "red" } },
      "1111"),
    createElement(
      "ul",
      { className: "news" },
      createElement("li", null, "10"),
      createElement("li", null, "20"),
      createElement("li", null, "30"))),
  document.getElementById("root")
)
// const root = ReactDOM.createRoot(document.getElementById('root'));
// root.render(
//   <div className='box'>
//     <h2 className='title'>1111</h2>
//     <ul className='news'>
//       <li>10</li>
//       <li>20</li>
//       <li>30</li>
//     </ul>
//   </div>
// )

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值