jsx语法的解析
ReactDOM.render(
<div className="box" style={{color: 'red'}}>dandan</div>,
document.getElementById('root')
)
1.首先基于babel的语法解析模块(babel-preset-react)把jsx语法编译为react.creacteElement(....)结构
<div className="box" style={{color: 'red'}}>dandan</div>
//编译成以下结构:
React.createElement("div", {
id: "div",
className: "box",
style: {color: 'red'}
}, "dandan")
2.执行React.createElement()函数,创建了一个对象(虚拟DOM)
// 根据传进来的值修改这个对象
// 1. type直接赋值给type
// 2. props中大部分属性都直接赋值给新对象props。
// 3. 但有一些比较特殊,如果是ref,key等值,我们需要把在props里面的值提取出来,创建两个新的对象存储,对象键就为ref,key,并将props里面的值删除
// 4.把传递进来的children作为新创建对象props中的一个属性(children为标签里的元素(可能是一个标签,文本或者更多的嵌套的标签))
// 编写createElement方法
// children有可能不止一个(如果有多个子元素就不止一个),也有可能一个没有
{
type: 'div'
ref: null
key: null
props: {
id: 'div',
className: 'box',
style: {color: 'red'}
__proto__: Object.prototype
}
- ReactDom.render() 将jsx语法最后生成的对象插入容器, 基于render方法把生成的对象动态创建为DOM元素,插入到指定容器里)
自己创建的createElement()函数
// children可能不止一个(如果有多个子元素就不止一个),也有可能一个没有,所以用...接取
function createElement(type, props, ...childrens) {
// props可能不会有值,当无值时为{}
props = props || {}
// 定义ref, key变量,用于赋值
let ref, key
if("key" in props) {
key = props.key
}else {
props.key = undefined
}
if("ref" in props) {
ref = props.ref
}else {
props.key = undefined
}
// 返回一个对象
return {type, props: {...props, children: childrens.length <= 1 ? childrens[0] : childrens}}
}
编写render方法 (作用:将创建的对象生成dom元素最后插入到页面当中)
function render(obj, container, callback) {
// obj已经从createElement里得到
// {
// type: 'div',
// props: {
// id: 'div',
// className: 'box',
// style: { color: 'red' },
// children: 'dandan'
// },
// ref: null,
// key: null
// }
// 首先结构赋值取出type, props
let {type, props} = obj || {}
//创建一个新元素
let newElement = document.createElement(type)
// 遍历props对象
for(let attr in props) {
// 检测是否为私有属性,如果不是则跳过此次循环
if(!props.hasOwnProperty(attr)) continue
// 检测该属性是否有值,如果没有则跳过此次循环
if(!props[attr]) continue
// 取出属性值,将值赋值给元素
let value = props[attr]
// 一些属性需要单独处理
// class
if(attr === 'className') {
newElement.setAttribute('class', value)
continue
}
// style
if(attr === 'style' && Object.prototype.toString.call(value) === '[object Object]') {
for(let styKey in value) {
if(value.hasOwnProperty(styKey)) {
newElement.style[styKey] = value[styKey]
}
}
continue
}
// children可能为一个值(字符串或者jsx对象),也可能为一个数组(数组每一项可能是字符串,也可能是字符串)
if(attr === 'children') {
//如果不是数组,表示为一个值,则让他变成数组便于处理
if(Object.prototype.toString.call(value) !== '[object Array]') {
value = [value]
}
value.forEach((item, index) => {
// 验证item类型,如果为对象则继续执行createElement方法,把创建的元素放到最开始的大盒子里
if(Object.prototype.toString.call(item) === '[object String]') {
let text = document.createTextNode(item)
newElement.appendChild(text)
}else {
render(item, newElement)
}
})
continue
}
newElement.setAttribute(attr, value)
}
container.appendChild(newElement)
callback && callback()
}
调用方法
render(createElement("div", {
id: "div",
className: "box",
style: {color: 'red'}
}, "dandan"), document.getElementById("root"), () => {
console.log('ok')
})
网友评论