JSX底层渲染机制
一,.步骤
1.把我们写的jsx语法编译为虚拟DOM【virtualDOM】
虚拟DOM对象:框架自己内部构建的一套对象体系(对象的相关成员都是React内部绑定的),基于这些属性描述出我们所构建视图中的DOM接的相关特征
@1基于babel-preset-react-app 把jsx编译为React.createElement(...)的格式。
只要是元素节点,必然会基于createElement进行处理!
React.createElement(ele,props,...children)
+ele: 元素标签名【或组件】
+props: 元素的属性集合(对象),如果没有任何的属性,则此值为null
+children: 第三个及其以后得参数,都是当前元素的子节点
如下图jsx
javascript
root.render{
<>
<h2 className='title' style={styleObj}>XXXX</h2>
<div className='box'>
<span>x</span>
<span>y</span>
</div>
</>
}
编译为
@再把CreateElement的方法执行,创建出VirtualDom对象【也有称为:JSX元素、JSX对象、ReactChild对象...】
javascript
//虚拟DOM对象
virtualDOM={
$$typeOf:Symbol(react.element),
ref:null,
key:null,
type:标签名【或组件】,
//存储了元素相关属性&子节点信息
props:{
元素的相关节点
children:子节点信息【没有子节点就没有则个属性、属性可能是一个值,也可能是一个数组】
}
}
javascript
/*createElement:创建虚拟DOM对象*/
export fucnction createElement(ele,props,...children){
let virtualDOM={
$$typeOf:Symbol('react.element'),
key:null,
key:null,
ref:null,
type:null.
props:{}
};
let len=children,length
virtualDOM.type=ele;
if(props){
virtualDOM.props={...props}
}
if(len===1){
virtualDOM.props.children=children[0]
}else if(len>1){
virtualDOM.props.children=children
}
return virtualDOM
}
2.构建的virtualDOM渲染为真实的DOM元素
真实DOM:浏览器页面中,最后渲染出来,让用户看见的DOM元素
基于ReactDOM中的render方法处理
v16
javascript
ReactDOM.render(
<>...</>
domcument.getElementById('root')
)
v18
javascript
const root = React.createRoot(dociment.getElementById('root'))
root,render(
<>...</>
)
补充:第一次渲染页面是直接从虚拟DOM ---> 真实ODM,但是后续视图更新的时候会经过一个DOM-DIFF的对比,计算出补丁包PATCH(两次视图差异部分),把PATCH补丁包进行渲染
javascript
/*render:把虚拟DOM变为真实DOM*/
export function render(virtualDOM,container){
let {type,props}=virtualDOM;
if(typeof type==='string'){
//存储的是标签名:动态创建这样一个标签
let ele=domcument.createElement(type);
//为标签设置相关属性&节点
each(props,(value,key)=>{
//classNmae的处理
if(key==='className'){
ele.className=value
return
}
//style的处理:value存储的是样式对象
if(key==='style'){
each(value,(val,attr)=>{
ele.style[attr]=val
})
return
}
//子节点的处理:value存储的children属性值
if(key==='children'){
let children = value
if(children.length===1){
children=[children]
}
children.forEach(child=>{
//子节点是文本节点:直接插入
if(typeof child==='string'){
ele.appendChild(domcument.createTextNode(child))
return;
}
//子节点又是一个虚拟ODM:递归处理
render(child,ele)
})
return
}
ele.setAttribute(key,value);
})
container.appendChild(ele)
}
}