React的简单实现
/**
* @param {*} type 元素的类型
* @param {*} config 配置对象
* @param {*} children 儿子或儿子们
*/
function createElement(type, config, children) {
if(config) {
delete config.__source;
delete config.__self;
}
let props = {...config};
// 有多个儿子变成数组
if(arguments.length > 3) {
children = Array.prototype.slice.call(arguments, 2);
}
props.children = children;
return {
type,
props
}
}
const React = {
createElement
}
export default React
ReactDOM.render实现
/**
* @param {*} vdom 虚拟dom
* @param {*} container 把虚拟转真实dom -> 放置的容器中
*/
function render(vdom, container) {
// 把虚拟dom变成真实dom
const dom = createDOM(vdom);
// 把真实的dom挂载到容器上面
container.appendChild(dom);
}
/**
* 虚拟dom -> 真实dom
* @param {*} vdom 虚拟dom
*/
function createDOM(vdom) {
// 如果是数字或者字符串 -> 真实的文本节点
if (["string", "number"].includes(typeof vdom)) {
return document.createTextNode(vdom);
}
// 否则是虚拟DOM对象,也就是react元素
let {type, props} = vdom;
let dom = document.createElement(type);
// 使用虚拟dom的属性添加给真实dom的属性
updateProps(dom, props);
// 处理children
// 只有一个儿子,为文本的时候
if(["string", "number"].includes(typeof props.children)) {
// 优化方案
dom.textContent = props.children;
} else if(typeof props.children === "object" && props.children.type) {
// 只有一个儿子,并且为虚拟dom对象
// **把儿子变成真实dom插在自己身上**
render(props.children, dom);// 递归
} else if (Array.isArray(props.children)) {
// 多个儿子
reconcileChildren(props.children, dom);
} else {
// 兜底的
document.textContent = props.children ? props.children.toString(): "";
}
return dom;
}
/**
*
* @param {*} dom 真实dom
* @param {*} newProps 新属性
*/
function updateProps(dom, newProps) {
for(let key in newProps) {
if(key === "children") continue;//单独处理children,不在这里处理
if(key === "style") {
let styleObj = props.style;
for(let attr in styleObj) {
dom.style[attr] = style[attr];
}
}else {
// className也是可以赋值给属性的
dom[key] = newProps[key];
}
}
}
/**
* 处理children是数组的情况
* @param {*} children 儿子组的虚拟dom
* @param {*} dom 父亲的真实dom
*/
function reconcileChildren(children, dom) {
for(let i = 0; i < children.length; i++) {
let childVdom = children[i];
// 递归
render(childVdom, dom);
}
}
const ReactDOM = {
render
}
export default ReactDOM;
这里是渲染的原理后续接着补充完整