首先我們來(lái)看一個(gè)最簡(jiǎn)單的hello world例子
function App() {
return (
<p className="title">hello world</p>
);
}
ReactDOM.render(<APP />, document.getElementById("root"));
在babel中轉(zhuǎn)化為如下代碼
function App() {
return React.createElement(
"p",
{ className: "title" },
"hello world"
);
}
ReactDOM.render(React.createElement(APP, null), document.getElementById("root"));
打印App(),返回的對(duì)象就是一個(gè)虛擬DOM
實(shí)現(xiàn)React.createElement
通過(guò)上文,我們可以知道jsx本質(zhì)是個(gè)語(yǔ)法糖。jsx片段會(huì)被轉(zhuǎn)譯成用React.createElement
方法包裹的代碼南窗。所以第一步帘瞭,我們來(lái)實(shí)現(xiàn)這個(gè)React.createElement
方法
function createElement(tag, attrs, ...children){
return {
tag,
attrs,
children
}
}
第一個(gè)參數(shù)是DOM節(jié)點(diǎn)的標(biāo)簽名
第二個(gè)參數(shù)是一個(gè)對(duì)象统捶,里面保存了所有的屬性
從第三個(gè)參數(shù)開(kāi)始七蜘,就是它的子節(jié)點(diǎn)。
我們的createElement方法返回的對(duì)象記錄了這個(gè)DOM節(jié)點(diǎn)所有的信息捕仔,換言之匕积,通過(guò)它我們就可以生成真正的DOM,這個(gè)記錄信息的對(duì)象我們稱之為虛擬DOM榜跌。
實(shí)現(xiàn)ReactDOM.render
我們來(lái)看這段代碼
ReactDOM.render(
React.createElement("p", { className: "title" }, "hello world"),
document.getElementById("root")
)
所以render
的第一個(gè)參數(shù)實(shí)際上接受的是createElement返回的對(duì)象闪唆,也就是虛擬DOM
而第二個(gè)參數(shù)則是掛載的目標(biāo)DOM
我們來(lái)實(shí)現(xiàn)這個(gè)render方法
function render(vnode, container) {
//當(dāng)vnode為字符串時(shí),渲染結(jié)果是一段文本
if (typeof vnode === "string") {
const textNode = document.createTextNode(vnode)
return container.appendChild(textNode)
}
const dom = document.createElement(vnode.tag)
//設(shè)置屬性
if (vnode.attrs) {
Object.keys(vnode.attrs).forEach(key => {
const value = vnode.attrs[key]
dom.setAttribute(key, value)
})
}
//遞歸渲染子節(jié)點(diǎn)
vnode.children.forEach(child=> render(child, dom))
return container.appendChild(dom)
}
參考資料