虚拟DOM的渲染机制
学习React必须知道React的两个方面,一个是虚拟DOM,另一个是Diff算法。今天我们先来看一下React的虚拟DOM的实现原理。
下面是虚拟DOM的一个简单实现原理,要是想深究的话,还是需要去阅读一下相关的源码部分。
原理: React会先将你的代码转换成一个javascript对象,然后再把这个javascript对象转换成真实的DOM。而这个javascript对象就是所谓的虚拟DOM。
实现步骤:
-
基于babel-preset-react-app把JSX变成
React.createElement(...)
。可以理解为JSX只是React.createElement的语法糖。<div className="box" style={{color: '#f00'}} index={0}> 123 <p>456</p> </div>
经过babel转换成下面的样子:
React.createElement("div", { className: "box", style: { color: '#f00' }, index: 0 }, "123", React.createElement("p", null, "456") );
- 第一项:标签名(或者函数组件、类组件)
- 第二项:标签上的属性值(没有属性默认是null)
- 第三项或者更多项:标签的子节点(文本节点或者元素节点-所有的元素节点都会重新走React.createElement())
-
执行
React.createElement(...)
会返回一个javascript对象,这个对象就是所谓的虚拟DOM。任何的创建更改都是都是对这个javascript对象进行的操作,事件监听时也是对这个javascript对象进行事件监听,会代理到原生的DOM上。
- createElement会返回一个虚拟对象
let VitrualDomObj = React.createElement(...)
,通过控制台打印出来VitrualDomObj可以看见:
- 虚拟dom:
实现原理:{ type:标签名或组件名 props:{ className: "box", index: 0, style: {color: "#f00"}, children:子节点内容(特点:没有子节点,则没有这一项,只有文本节点的时候,是一个字符串,有多个子节点的时候是一个数组) } }
export function mycreateElement(type,props,...childs){ let obj = {} obj.type = type; obj.props = props || {}; if(childs.length > 0){ obj.props.children = childs.length === 1 ? childs[0] : childs; } return obj; }
- createElement会返回一个虚拟对象
-
把这个虚拟DOM通过render函数转换成真实的DOM
// 使用render转换成真实dom myrender( VitrualDomObj , document.getElementById('root'));
实现原理:
export function myrender(VitrualDomObj, container, callback) { let { type, props } = VitrualDomObj let element = document.createElement(type); for (let key in props){ if(!props.hasOwnProperty(key)) return; if(key === 'className'){ element.className = props[key]; continue; } if(key === 'style'){ let sty = props[key]; for(let attr in sty){ if(!sty.hasOwnProperty(attr)) return; element.style[attr] = sty[attr]; } continue; } if(key === 'children'){ let children = props[key]; children = Array.isArray(children) ? children : [children]; children.forEach((item)=>{ if(typeof item === 'string'){ element.appendChild(document.createTextNode(item)) return; } myrender(item,element); }) continue; } element.setAttribute(key,props[key]); } container.appendChild(element); callback && callback(); }
以上就是一个简版的虚拟dom实现原理,总结一下,总共分为三步:
- babel将jsx语法转成React.createElement(…)的形式。
- React.createElement函数将参数转换成javascript对象的形式。
- ReactDOM.render将javascript对象转换成真实的dom插入到指定的dom容器中。