目錄
- 1 前言
- 2 實現(xiàn)Virtual DOM的2種形態(tài)
- 1 純JSON格式
- 2 非JSON格式
- 3 下一篇
- 4 參考
前言
回顧React創(chuàng)建組件的三種方式:(其中React.createClass 16版本后已廢棄)

無論是純函數(shù)還是組件,都返回一個
(<div>...</div>)HTML格式的內(nèi)容,這段代碼并不是合法的js代碼,它是一種被稱為jsx的語法擴展,通過它我們就可以很方便的在js代碼中書寫html片段。[1]
本質(zhì)上,JSX是語法糖,上面這段代碼會被babel轉(zhuǎn)換成如下代碼
const title = React.createElement(
'h1',
{ className: 'title' },
'Hello, world!'
);
你可以在babel官網(wǎng)提供的在線轉(zhuǎn)譯測試jsx轉(zhuǎn)換后的代碼,這里有一個稍微復雜一點的例子
如何將轉(zhuǎn)義后的數(shù)據(jù)渲染到瀏覽器中,本篇文章將介紹2種方式,這里為了更好理解,完整例子都模仿React寫法實現(xiàn)。
實現(xiàn)Virtual DOM的2種形態(tài)
不依賴第三方庫
用js對象模擬DOM樹可以有2種形態(tài):純JSON格式和非JSON格式
1.純JSON數(shù)據(jù)
{type:"...", props: {...}, children: [...]}
{
type:'ul',
props:{},
children:[
{
type:'li',
props:{class:'list'},
children:[
{
type:'input',
props:{value:'Niko',class:'list',keyup:this.change},
children:[]},
]
},
{
type:'li',
props:{},
children:['Bellic']}
]
}
| 屬性 | 類型 | 描述 |
|---|---|---|
| type | string | DOM 節(jié)點名稱 |
| props | object | DOM屬性attrs或events函數(shù) |
| children | array[str/obj] | 數(shù)組內(nèi)為對象時表示子節(jié)點,循環(huán)上述;字符串時為標簽內(nèi)容 |
設(shè)置type
let $el = document.createElement(type)
設(shè)置props
從上述表中可以看出,不僅可以添加class等attrs屬性,
$el.setAttribute(propName, propValue)
有些元素還有添加事件的需求。
但是JSON格式最終只能存儲字符串,不能存儲一個可執(zhí)行的函數(shù)更不用說this的作用域,所以處理事件可以使用addEventListener(…)注冊事件,值得注意的是這里的事件類型就不能添加on-*前綴了。
if(typeof propValue === 'function'){
//props events
$el.addEventListener(
propName,
propValue
);
}else {
//props attrs
$el.setAttribute(propName, propValue)
}
設(shè)置children
當標簽內(nèi)不再添加標簽,children需要設(shè)置為[string]表示標簽的內(nèi)容。當標簽內(nèi)為一系列子標簽時,格式將和上一次一樣循環(huán)。在實現(xiàn)渲染時很容易想到利用遞歸進行插值
function createElement(node){
node.children.map(child=>{
$el.appendChild(createElement(child))
});
//最終目的是要返回$el
return $el
}
完整代碼戳這里??
https://gist.github.com/1uokun/bcfaec28d8c5051be343ca390bb3001e
拓展
Virtual DOM差異化對比[2]
setState和props傳遞實現(xiàn)[4]
2.非JSON格式
JSX轉(zhuǎn)義格式,和1區(qū)別在于DOM樹每一層都有一個執(zhí)行函數(shù),
var el = React.createElement;
var ul = el('ul', {id: 'list'}, [
el('li', {class: 'item'}, ['Item 1']),
el('li', {class: 'item'}, ['Item 2']),
el('li', {class: 'item'}, ['Item 3'])
])
這種格式實現(xiàn)就比較容易理解,針對每一層Virtual DOM進行解析
function createElement(tag, attrs, children) {...}
完整代碼戳這里??
https://gist.github.com/1uokun/e4ed774cb523bbc5425266119de520e5
下一篇
前面大致了解了JSX工作原理,不過都是用靜態(tài)HTML實現(xiàn),并且數(shù)據(jù)格式較繁瑣,如何舒舒服服寫JSX格式的代碼,又能自動轉(zhuǎn)換成合法的JavaScript?自然會想到前端工程化和webpack工具
下一節(jié)將介紹不依賴React如何使用webpack配置并打包JSX:Use JSX without React 2:編譯JSX和Component實現(xiàn)
參考
- [1] 依賴React和React-dom實現(xiàn)JSX和虛擬DOM
慕課筆記 - [2] 深度剖析:如何實現(xiàn)一個 Virtual DOM 算法
胡子大哈 - [3] 如何實現(xiàn)一個自己的Virtual DOM
medium.com - [4] 如何實現(xiàn)一個自己的Virtual DOM 2: Props & Events
medium.com - [5] can i use jsx without React to inline html in script?
stackoverflow