看不到的React
React的JSX语法
JSX语法与原生语法的不同之处
| JSX | 原生 | |
|---|---|---|
| class类名 | className | class |
| style | 需要写对象 | 直接写字符串 |
JSX语法中使用变量
❝在
❞JSX语法中使用变量需要{}来使用,并且不能是对象等引用数据类型(数组除外,但是如果数组中包含对象也不行)
JSX的编译
依靠babel-preset-react-app来进行编译
JSX的语法可以通过babel-preset-react-app来进行编译,通过编译之后变为CREATE-ELEMENT格式,React.createElement([标签名],[PROPS|NULL],...) 有几个子节点,从第三个实参开始分别是每一个子节点的处理(文本节点直接就是文本内容,元素节点还需要再一次CREATE-ELEMENT处理)
<div className="box" id="box" index="1">
学习React
<span className="text">
欢迎大家来学习
<i></i>
</span>
</div>
// 转换为
React.createElement("div", {
className: "box",
id: "box",
index: "1"
}, "学习React", React.createElement("span", {
className: "text"
}, "欢迎大家来学习", React.createElement("i", null)));
执行createElement变为虚拟DOM
执行CREATE-ELEMENT
* =>返回一个对象 {
* key:null,
* ref:null,
* type:标签名/组件,
* props:{
* xxx:xxx, //=>给元素标签上设置的属性(REF/KEY除外)
* //=>没有子节点则没有children选项,有子节点才有children,只有一个字节点它的值是单个值,如果有多个子节点,它的值是一个数组
* children:单个值(字符串/对象) 或者 数组
* }
* }
最后将虚拟DOM通过render变为真实DOM插入到容器中
/*
* createElement:创建出一个虚拟的DOM对象
*/
export function createElement(type, props, ...childs) {
let jsxOBJ = {
type,
props: {},
key: null,
ref: null
};
if (props) {
//=>处理KEY和REF
if (props.hasOwnProperty('key')) {
jsxOBJ.key = props.key;
delete props.key;
}
if (props.hasOwnProperty('ref')) {
jsxOBJ.ref = props.ref;
delete props.ref;
}
jsxOBJ.props = Object.assign(jsxOBJ.props, props);
}
//=>children处理
if (childs.length > 0) {
childs = childs.length === 1 ? childs[0] : childs;
jsxOBJ.props.children = childs;
}
return jsxOBJ;
}
/*
* render:把虚拟的DOM变为真实的DOM
*/
export function render(jsxOBJ, container, callback) {
let {
type,
props
} = jsxOBJ;
// 1.根据TYPE创建一个DOM元素对象(真实DOM)
let element = document.createElement(type);
// 1.1根据PROPS中的属性,依次给创建的元素进行设置
for (let key in props) {
if (!props.hasOwnProperty(key)) break;
// 1.2关于某些属性的特殊处理:className/style/children
if (key === 'className') {
element.className = props['className'];
continue;
}
if (key === 'style') {
let styOBJ = props['style'];
for (let styKey in styOBJ) {
if (!styOBJ.hasOwnProperty(styKey)) break;
element['style'][styKey] = styOBJ[styKey];
}
continue;
}
if (key === 'children') {
let val = props['children'],
childrenArr = Array.isArray(val) ? val : [val];
// 1.3迭代所有子元素,如果是字符串直接做为文本插入到新创建的元素中,如果是一个新的虚拟DOM对象,递归调用RENDER,再次创建元素标签超入到新创建的元素中
childrenArr.forEach(item => {
if (typeof item === "string") {
element.appendChild(document.createTextNode(item));
return;
}
render(item, element);
});
continue;
}
element.setAttribute(key, props[key]);
}
// 2.把创建的元素对象添加到指定的容器中
container.appendChild(element);
callback && callback();
}
本文使用 mdnice 排版