从上一节html DOM转换为Element
元素对象可以看出,将DOM结构手动转换为元素对象是比较繁琐的,所以需要提供一种方式来简化元素对象的创建,这种方式就是JSX
。
JSX:简化元素对象书写
JSX
提供了一些语法糖,来替代手动创建Element
对象,我们可以这么书写以替代上一节的DOM树描述:
const element = (
<div id="container">
<input value="foo" type="text" />
<a href="/bar">bar</a>
<span onClick={e => alert("Hi")}>click me</span>
</div>
);
对应的Element
对象为:
const element = {
type: "div",
props: {
id: "container",
children: [
{ type: "input", props: { value: "foo", type: "text" } },
{
type: "a",
props: {
href: "/bar",
children: [{ type: "TEXT ELEMENT", props: { nodeValue: "bar" } }]
}
},
{
type: "span",
props: {
onClick: e => alert("Hi"),
children: [{ type: "TEXT ELEMENT", props: { nodeValue: "click me" } }]
}
}
]
}
};
babel-loader:将JSX转换为有效的JS
JSX
并不是有效的javascript
,为了使浏览器能理解,需要将JSX
代码由预处理转化为有效的JS,通常使用babel-loader
将JSX
转换为JS。
babel-loader
会将上述JSX
代码转换为一个递归使用createElement
函数的对象:
const element = createElement(
"div",
{ id: "container" },
createElement("input", { value: "foo", type: "text" }),
createElement(
"a",
{ href: "/bar" },
"bar"
),
createElement(
"span",
{ onClick: e => alert("Hi") },
"click me"
)
);
createElement函数:将JSX转换为Element对象
上面描述了babel-loader
会将JSX
转换为上述形式的JS,递归使用了createElement
函数,所以需要支持将JSX
转换为Element
的createElement
函数。
- 入参:
type
(元素的html标签类型),props
(元素的属性及子元素) - 出参:
Eelemnt
对象
createElement
需要创建一个props
对象,将其分配给第二个参数中的所有值,将该children
属性设置为第二个参数后面的所有参数,然后返回一个Element
对象({ type, props }
)。
function createElement(type, config, ...args) {
const props = Object.assign({}, config);// 合并
const hasChildren = args.length > 0; // 是否有孩子
props.children = hasChildren ? [].concat(...args) : [];
return { type, props }; // Didact元素的数据结构-类型{type}与属性{props}
}
总结
这两节我们介绍了3个概念之间的关系:JSX
、element
和html DOM,以及两个函数:createElement()
和render()
,它们之间的关系如下图: