ReactDOM.render的渲染原理
在react项目中,之所以可以在函数/组件中直接写模板结构,是因为最后babel都会帮我们把这些模板转译成 React.createElemen(config) 的形式,这也就是为什么我们在每一个组件中明明没有主动调用React,但是却要引入react的原因。
// 举例
import React from 'react';
import ReactDOM from 'react-dom';
let h = React.createElement(
'div',{className:'box',style:{fontSize:'30px', color:'green'}},'第一个儿子',
React.createElement('h2',{style:{color:'red',textAlign: 'center'}},'第二个儿子')
);
let p = <div className='box' style={{fontSize:'30px', color:'green'}}>
第一个儿子
<h2 style={{color:'red',textAlign: 'center'}}>第二个儿子</h2>
</div>
ReactDOM.render(<>
{h}
{p}
</>,
document.getElementById('root'));
// p和h渲染的页面是一样的
复制代码
渲染结果:
简单实现 React.createElement 和 ReactDOM.render 的功能
let React = {
createElement(type, attrs,...children){
// 第一步:创建真实的DOM
let el = document.createElement(type);
// 第二步:对行内属性进行处理
let keys = Object.keys(attrs);
for(let i=0; i<keys.length; i++) {
let key = keys[i];
switch(key) {
case 'className':
el.setAttribute('class', attrs[key]);
break;
case 'htmlFor':
el.setAttribute('for', attrs[key]);
break;
case 'style':
let str = ''
Object.keys(attrs.style).forEach(item=>{
str += `${React.changeStr(item)}:${attrs.style[item]};`
});
el.setAttribute('style', str);
break;
default:
el.setAttribute(key, attrs[key]);
}
}
// 第三步:处理后代元素
children.forEach(child=>{
if(typeof child === 'string') {
el.appendChild(document.createTextNode(child))
}else {
// console.log(child, 'else')
el.appendChild(child)
}
})
// 最后,返回创建的真实DOM
return el;
},
changeStr(str){
// 辅助函数:目的是将驼峰命名的属性转为串式命名
// 例如:fontSize -> font-size
return str.replace(/[A-Z]/g, b=>{
return '-' + b.toLowerCase();
}).replace(/^-/, '')
}
};
let ReactDOM = {
render(el, container){
// el 是React.createElement 处理之后的拿到的真实DOM,直接操作皆可
// 将转化后拿到的真实DOM插入到container中
container.appendChild(el);
}
}
let h = React.createElement(
'div',{className:'box',style:{fontSize:'30px', color:'green'}},'第一个儿子',
React.createElement('h2',{style:{color:'red',textAlign: 'center'}},'第二个儿子')
);
ReactDOM.render(h, document.getElementById('root'));
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END