/* 创建虚拟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>
// )