[React]虚拟DOM
1.虚拟DOM(virtual DOM)
我们在render()方法中书写的JSX代码,既有js代码又有html代码,但是实际上浏览器不能识别JSX。
let element = (<div className="red"> <span>hehe</span> </div>)
需要通过babel-loader将其转化为js代码。实际上就是转为React中的createElement()方法调用。
var element = React.createElement("div", { className: "red" }, React.createElement("span", null, "hehe"));
该方法返回一个对象,这个对象的内容和DOM类似,但是不是真实的DOM,所以称之为虚拟DOM。
{ "type": "div", "props": { "className": "red", "children": { "type": "span", "props": { "children": "hehe" } } } }
最后浏览器展示的DOM是通过ReactDOM.render()方法处理后,成为真实DOM。
2.createElement()方法模拟实现
function createElement(type, config, children) { console.log(children) const props = {}; for (let propName in config) { props[propName] = config[propName]; } const childrenLength = arguments.length - 2; if (childrenLength === 1) { props.children = children; // 为元素,文本,数字 } else if (childrenLength > 1) { // 为数组 props.children = Array.from(arguments).slice(2); } return { type, props} }
3.render方法模拟实现
function render(element, container) { if (typeof element === 'string' || typeof element === 'number') { // 文本或者数字 container.appendChild(document.createTextNode(element)); return; } let type = element.type; let props = element.props; if (typeof type === 'function') { // 函数组件或者类组件 if (type.isComponent) { // 类 element = (new type(props)).render(); } else { element = type(props); } type = element.type; props = element.props; } let domEle = document.createElement(type); for (let propName in props) { if (propName === 'className') { domEle.className = props[propName]; } else if(propName === 'style') { const styleObj = props[propName]; for(let styleProp in styleObj) { domEle.style[styleProp] = styleObj[styleProp]; } } else if(/^on[A-Z]/.test(propName)) { domEle[propName.toLowerCase()] = props[propName]; } else if(propName === 'children') { const children = Array.isArray(props[propName]) ? props[propName] : [props.children]; children.forEach(child => render(child, domEle)); } } container.appendChild(domEle); }