精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

手寫簡易前端框架:Vdom 渲染和 jsx 編譯

開發 前端
本文我們實現了 vdom 的渲染。vdom 是描述界面的對象,它的渲染就是通過 createElement、createTextNode 等 api 來遞歸創建和組裝元素、文本等 dom 的過程。

作為前端工程師,前端框架幾乎每天都要用到,需要好好掌握,而對某項技術的掌握程度可以根據是否能實現一個來判斷。手寫一個前端框架對更好的掌握它是很有幫助的事情。

現代前端框架經過多年的迭代都已經變得很復雜,理清它們的實現原理變得困難重重。所以我想寫一個最簡單版本的前端框架來幫助大家理清思路。

一個完整的前端框架涉及到的內容還是比較多的,我們一步步的來,這篇文章來實現下 vdom 的渲染。

vdom 的渲染

vdom 全稱 virtual dom,用來聲明式的描述頁面,現代前端框架很多都基于 vdom。前端框架負責把 vdom 轉為對真實 dom 的增刪改,也就是 vdom 的渲染。

那么 vdom 是什么樣的?又是怎么渲染的呢?

dom 主要是元素、屬性、文本,vdom 也是一樣,其中元素是 {type、props、children} 的結構,文本就是字符串、數字。

比如這樣一段 vdom:

{
type: 'ul',
props: {
className: 'list'
},
children: [
{
type: 'li',
props: {
className: 'item',
style: {
background: 'blue',
color: '#fff'
},
onClick: function() {
alert(1);
}
},
children: [
'aaaa'
]
},
{
type: 'li',
props: {
className: 'item'
},
children: [
'bbbbddd'
]
},
{
type: 'li',
props: {
className: 'item'
},
children: [
'cccc'
]
}
]
}

不難看出,它描述的是一個 ul 的元素、它有三個 li 子元素,其中第一個子元素有 style 的樣式、還有 onClick 的事件。

前端框架就是通過這樣的對象結構來描述界面的,然后把它渲染到 dom。

這樣的對象結構怎么渲染呢?

明顯要用遞歸,對不同的類型做不同的處理。

  • 如果是文本類型,那么就要用 document.createTextNode 來創建文本節點。
  • 如果是元素類型,那么就要用 document.createElement來創建元素節點,元素節點還有屬性要處理,并且要遞歸的渲染子節點。

所以,vdom 的 render 邏輯就是這樣的:

if (isTextVdom(vdom)) {
return mount(document.createTextNode(vdom));
} else if (isElementVdom(vdom)) {
const dom = mount(document.createElement(vdom.type));
for (const child of vdom.children) {
render(child, dom);
}
for (const prop in vdom.props) {
setAttribute(dom, prop, vdom.props[prop]);
}
return dom;
}

文本的判斷就是字符串和數字:

function isTextVdom(vdom) {
return typeof vdom == 'string' || typeof vdom == 'number';
}

元素的判斷就是對象,并且 type 為標簽名的字符串:

function isElementVdom(vdom) {
return typeof vdom == 'object' && typeof vdom.type == 'string';
}

元素創建出來之后如果有父節點要掛載到父節點,組裝成 dom 樹:

const mount = parent ? (el => parent.appendChild(el)) : (el => el);

所以,完整的 render 函數就是這樣的:

const render = (vdom, parent = null) => {
const mount = parent ? (el => parent.appendChild(el)) : (el => el);
if (isTextVdom(vdom)) {
return mount(document.createTextNode(vdom));
} else if (isElementVdom(vdom)) {
const dom = mount(document.createElement(vdom.type));
for (const child of vdom.children) {
render(child, dom);
}
for (const prop in vdom.props) {
setAttribute(dom, prop, vdom.props[prop]);
}
return dom;
}
};

其中,元素的 dom 還要設置屬性,比如上面 vdom 里有 style 和 onClick 的屬性要設置。

style 屬性是樣式,支持對象,要把對象合并之后設置到 style,而 onClick 屬性是事件監聽器,用 addEventListener 設置,其余的屬性都用 setAttribute 來設置。

const setAttribute = (dom, key, value) => {
if (typeof value == 'function' && key.startsWith('on')) {
const eventType = key.slice(2).toLowerCase();
dom.addEventListener(eventType, value);
} else if (key == 'style' && typeof value == 'object') {
Object.assign(dom.style, value);
} else if (typeof value != 'object' && typeof value != 'function') {
dom.setAttribute(key, value);
}
}

就這樣,vdom 的渲染邏輯就完成了。

用上面那段 vdom 渲染試下效果:

render(vdom, document.getElementById('root'));

vdom 的渲染成功!

小結一下:

「vdom 會遞歸的進行渲染,根據類型的不同,元素、文本會分別用 createTextNode、createElement 來遞歸創建 dom 并組裝到一起,其中元素還要設置屬性,style、事件監聽器和其他屬性分別用 addEventListener、setAttribute 等 api 進行設置。」

「通過不同的 api 創建 dom 和設置屬性,這就是 vdom 的渲染流程。」

但是,vdom 寫起來也太麻煩了,沒人會直接寫 vdom,一般是通過更友好的 DSL(領域特定語言) 來寫,然后編譯成 vdom,比如 jsx 和 template。

這里我們使用 jsx 的方式,因為可以直接用 babel 編譯。

jsx 編譯成 vdom

上面的 vdom 改為 jsx 來寫就是這樣的:

const jsx = <ul className="list">
<li className="item" style={{ background: 'blue', color: 'pink' }} onClick={() => alert(2)}>aaa</li>
<li className="item">bbbb</li>
<li className="item">cccc</li>
</ul>

render(jsx, document.getElementById('root'));

明顯比直接寫 vdom 緊湊了不少,但是需要做一次編譯。

配置下 babel 來編譯 jsx:

module.exports = {
presets: [
[
'@babel/preset-react',
{
pragma: 'createElement'
}
]
]
}

編譯產物是這樣的:

const jsx = createElement("ul", {
className: "list"
}, createElement("li", {
className: "item",
style: {
background: 'blue',
color: 'pink'
},
onClick: () => alert(2)
}, "aaa"), createElement("li", {
className: "item"
}, "bbbb"), createElement("li", {
className: "item"
}, "cccc"));
render(jsx, document.getElementById('root'));

為啥不直接是 vdom,而是一些函數呢?

因為這樣會有一次執行的過程,可以放入一些動態邏輯,

比如從 data 取值:

const data = {
item1: 'bbb',
item2: 'ddd'
}
const jsx = <ul className="list">
<li className="item" style={{ background: 'blue', color: 'pink' }} onClick={() => alert(2)}>aaa</li>
<li className="item">{data.item1}</li>
<li className="item">{data.item2}</li>
</ul>

會編譯成:

const data = {
item1: 'bbb',
item2: 'ddd'
};
const jsx = createElement("ul", {
className: "list"
}, createElement("li", {
className: "item",
style: {
background: 'blue',
color: 'pink'
},
onClick: () => alert(2)
}, "aaa"), createElement("li", {
className: "item"
}, data.item1), createElement("li", {
className: "item"
}, data.item2));

這叫做 render function,它執行的返回值就是 vdom。

這個 render function 名字之所以是 createElement,是因為我們上面 babel 配置里指定了 pragma 為 createElement。

render function 就是生成 vdom 的,所以實現很簡單:

const createElement = (type, props, ...children) => {
return {
type,
props,
children
};
};

我們來測試下改為 jsx 之后的渲染:

渲染成功!

我們在 vdom 的基礎上更進了一步,通過 jsx 來寫一些動態邏輯,然后編譯成 render function,執行之后產生 vdom。

這樣比直接寫 vdom 更簡單,可以做更靈活的 vdom 生成邏輯。

代碼上傳到了 github:https://github.com/QuarkGluonPlasma/frontend-framework-exercize

總結

手寫前端框架是更好的掌握它的最直接的方式,我們會逐步實現一個功能完整的前端框架。

本文我們實現了 vdom 的渲染。vdom 是描述界面的對象,它的渲染就是通過 createElement、createTextNode 等 api 來遞歸創建和組裝元素、文本等 dom 的過程,其中元素節點還需要設置屬性,style、event listener 等屬性會用不同的 api 設置。

雖然最終是 vdom 的渲染,但是開發時不會直接寫 vdom,而是通過 jsx 來描述頁面,然后編譯成 render function,執行后產生 vdom。這樣寫起來更簡潔,而且支持動態邏輯。(jsx 的編譯使用 babel,可以指定 render function 的名字)

vdom 渲染和 jsx 是前端框架的基礎,其他的功能比如組件是在這個基礎之上實現的,下篇文章我們就來實現組件的渲染。

責任編輯:姜華 來源: 神光的編程秘籍
相關推薦

2022-01-25 18:11:55

vdomclassfunction

2022-01-24 13:46:24

框架

2022-08-14 23:04:54

React前端框架

2022-07-06 08:30:36

vuereactvdom

2021-06-04 05:16:33

瀏覽器js源碼

2021-06-07 00:15:26

瀏覽器HtmlParser

2024-02-02 08:33:00

Vue模板性能

2017-04-12 11:46:46

前端瀏覽器渲染機制

2022-05-11 15:08:52

驅動開發系統移植

2010-12-29 09:51:29

前端基礎框架

2022-02-11 13:44:56

fiber架構React

2016-12-08 10:57:08

渲染引擎前端優化

2021-07-04 10:07:04

Virtual DO閱讀源碼虛擬DOM

2025-09-01 00:00:02

2022-01-10 11:04:41

單鏈表面試編程

2019-08-01 15:19:26

前端開發技術

2015-07-14 10:11:48

前端框架語言

2024-07-01 00:00:03

2020-12-10 06:01:20

前端Compose方法

2023-02-27 09:38:36

Springbootstarter
點贊
收藏

51CTO技術棧公眾號

亚洲成人av在线播放| 国产精品乱码一区二区三区软件| 国内精品久久久久| 人妻在线日韩免费视频| 中文av在线全新| 中文字幕乱码一区二区免费| 99精彩视频| 区一区二在线观看| 永久91嫩草亚洲精品人人| 亚洲电影在线观看| 国内外成人免费在线视频| 后进极品白嫩翘臀在线播放| 久久久国产午夜精品 | 91玉足脚交嫩脚丫在线播放| 欧美一区二区三区高清视频| 日韩一区二区免费在线观看| 97视频在线免费播放| 久做在线视频免费观看| 91麻豆国产香蕉久久精品| 成人欧美在线视频| 男人天堂av在线播放| 黄色成人av网站| 色噜噜久久综合伊人一本| 国产精品久久不卡| 中文字幕一区二区三区日韩精品| 欧美最猛黑人xxxxx猛交| 加勒比成人在线| 欧美成年黄网站色视频| 久久久美女毛片| 国产精品视频500部| 97人妻精品一区二区三区动漫| 国产欧美日韩一级| 欧美激情精品久久久| 亚洲精品久久久久久国| 精品久久久久久久久久久aⅴ| 欧美精品一区二区三区蜜桃视频| 中文字幕1234区| 欧美日韩在线精品一区二区三区激情综合 | 日韩精品一区二区三区| 亚洲成人资源在线| 97在线免费视频观看| 色影院视频在线| 国产人久久人人人人爽| 欧美日韩成人一区二区三区| 五月天婷婷社区| 成人免费视频网站在线观看| 91久久极品少妇xxxxⅹ软件| 一级片在线观看视频| 奇米影视7777精品一区二区| 国产va免费精品高清在线观看| 国产视频91在线| 亚洲另类视频| 2019中文字幕在线观看| 日韩精品一区二区av| 亚洲午夜激情在线| 久久久天堂国产精品女人| 久久久一区二区三区四区| 欧美黄色大片网站| 欧美大片免费看| 国产真实乱偷精品视频| 亚洲调教视频在线观看| 91国在线精品国内播放| 久久久久久久久久免费视频| 亚洲综合社区| 国产精品久久久久免费a∨| 人人妻人人爽人人澡人人精品| 久久字幕精品一区| 国产精品久久久一区| 中文字幕+乱码+中文字幕明步| 老色鬼久久亚洲一区二区| 国产97在线|日韩| 中文字幕黄色av| 精品一区二区在线看| 91日本视频在线| 亚洲男人天堂久久| 99热在这里有精品免费| 欧美一区少妇| 黄网站免费在线观看| 一区二区三区四区亚洲| 日韩av高清在线看片| 欧美黑人粗大| 91精品在线免费观看| 一二三区视频在线观看| 人体久久天天| 深夜成人在线观看| 久久伊人成人网| 国产亚洲精品成人| 五月天激情婷婷| 成人免费视频一区二区| 久久偷窥视频| 午夜激情视频在线观看| 亚洲精品国产a久久久久久| 精品久久久无码人妻字幂| 成人影院在线播放| 色婷婷av一区二区三区软件| 欧美成人乱码一二三四区免费| 国产一区一区| 亚洲乱码国产乱码精品精| 99re6热在线精品视频| 激情综合激情| 国产免费久久av| 天天av天天翘| 国产精品私房写真福利视频| 人妻av无码专区| 主播大秀视频在线观看一区二区| 日韩一区二区视频| 国产在线观看h| 好看的日韩av电影| 欧美在线视频观看| 99久久免费国产精精品| 亚洲一级大片| 欧美午夜片在线看| 午夜男人的天堂| 99热国内精品| 欧美一级片免费在线| 国产情侣av在线| 久久日韩精品一区二区五区| 99久久99久久精品| 精品国产黄a∨片高清在线| 亚洲精品第一国产综合精品| 日韩黄色免费观看| 日本不卡一二三区黄网| 国产在线视频欧美一区二区三区| 毛片在线看网站| 色综合av在线| yy6080午夜| 午夜日韩电影| 亚洲一区二区中文| 日本高清中文字幕在线| 在线免费观看成人短视频| 亚洲av无码一区二区三区网址| 最新国产精品久久久| 国产精品久久久久久久久| 亚洲 精品 综合 精品 自拍| 亚洲综合成人在线视频| 四川一级毛毛片| 四季av一区二区凹凸精品| 国产精品久久久久福利| 欧美偷拍视频| 激情av一区二区| 国产精品九九视频| 欧美色图麻豆| av资源站久久亚洲| 日本天码aⅴ片在线电影网站| 欧美一区二区三区视频免费播放 | 俺去啦;欧美日韩| 中文字幕乱码人妻无码久久 | 永久免费看片直接| 免费高清视频精品| 亚洲高清在线观看一区| 免费一级欧美在线观看视频| 有码中文亚洲精品| 一二区在线观看| 国产精品国模大尺度视频| 欧美第一页浮力影院| 亚州av乱码久久精品蜜桃| 成人精品在线观看| 在线观看av免费| 日韩精品资源二区在线| 国产一级视频在线观看| 93久久精品日日躁夜夜躁欧美| 日韩中字在线观看| 亚洲aaa级| 国产精品免费网站| 黄色成年人视频在线观看| 日韩视频一区二区三区在线播放| 久草网在线观看| 99久久99久久精品免费看蜜桃| 北条麻妃在线视频观看| 国产免费av一区二区三区| 国产精品xxxxx| 麻豆系列在线观看| 亚洲变态欧美另类捆绑| 日本中文字幕第一页| 中文字幕欧美日韩一区| 91亚洲精品久久久蜜桃借种| 国内自拍视频一区二区三区| 久久综合狠狠综合久久综青草| 色成人免费网站| 蜜臀久久99精品久久久久久宅男| 女人18毛片一区二区三区| 色婷婷综合久久久久中文 | 精品久久久国产精品999| 成人黄色免费网址| 国产在线一区二区| 亚洲美免无码中文字幕在线| 成人羞羞网站| 国产不卡一区二区在线观看| a日韩av网址| 日韩小视频在线| 色欲久久久天天天综合网| 在线观看日韩一区| 黄色一级免费视频| 国产日韩欧美高清| 制服.丝袜.亚洲.中文.综合懂| 国产美女一区| 亚洲成人动漫在线| 国产欧美一区| 成人动漫在线视频| 精品国产欧美日韩一区二区三区| 久久国产精品久久久久久久久久| 亚洲欧洲精品视频| 欧美一区午夜视频在线观看| 久久久久亚洲av成人毛片韩| 亚洲欧美一区二区三区国产精品| 亚洲最大免费视频| 国产精品18久久久久久vr| 成人一级片网站| 国产精品草草| 中文字幕一区二区三区精彩视频| 女人抽搐喷水高潮国产精品| 91在线观看免费高清完整版在线观看| 日本不良网站在线观看| 欧美成人免费在线视频| 成人在线观看黄色| 亚洲精品久久久一区二区三区| 91在线精品入口| 色综合天天综合网天天看片| 久久久久亚洲av成人片| 综合久久久久久久| 国产探花视频在线播放| av在线不卡观看免费观看| 99中文字幕在线| 日本免费在线视频不卡一不卡二 | 美女尤物国产一区| 国模吧无码一区二区三区| 欧美啪啪一区| 日本精品免费视频| 欧美成人自拍| 色一情一乱一伦一区二区三区| 欧美性生活一级片| 国产另类自拍| 国产乱人伦精品一区| 3d精品h动漫啪啪一区二区| 男人亚洲天堂| 国产精品亚洲аv天堂网| 日韩免费小视频| 国产精品18久久久久久麻辣| 欧美一级大黄| 国产高清视频一区三区| 波多野结衣亚洲| 日本最新高清不卡中文字幕| 亚洲人成在线网站| 欧美亚洲国产视频小说| 亚洲欧美韩国| 欧洲成人在线视频| 欧美日韩大片| 国产精品xxxxx| 国产精品伦一区二区| 国产乱人伦真实精品视频| 久久精品资源| 国产精品福利网站| 国产91在线精品| 成人黄色免费在线观看| 国产aⅴ精品一区二区四区| 91精品国产高清久久久久久91裸体| 国产欧美视频在线| 99国产在线| 久久1电影院| 欧美亚洲一级二级| 欧美一二区在线观看| 在线视频欧美一区| 欧美1区2区| 成人一区二区免费视频| 久久久久久婷| 日日干夜夜操s8| 国产精品88av| 久久人人爽人人人人片| 久久精品一级爱片| 乱老熟女一区二区三区| 亚洲精品美腿丝袜| 国产成人在线播放视频| 91成人在线精品| 92久久精品一区二区| 欧美大肚乱孕交hd孕妇| 五月天激情婷婷| 在线成人免费网站| 羞羞网站在线免费观看| 日本久久91av| 欧美少妇激情| 激情伦成人综合小说| 日韩免费高清| 免费一级特黄毛片| 日本va欧美va精品| 亚洲成人精品在线播放| 久久综合久色欧美综合狠狠| 国精产品一区一区| 亚洲成人av电影在线| 中文天堂在线播放| 欧美精品一区视频| 尤物网在线观看| 国产69精品久久久久9| 粉嫩91精品久久久久久久99蜜桃| 99在线影院| 成人在线免费视频观看| 免费看毛片的网址| 久久国产精品第一页| 午夜久久久久久久| 亚洲男女一区二区三区| 无码人妻一区二区三区线| 欧美一区二区精美| 国产私人尤物无码不卡| 欧美精品videosex极品1| 91精品美女| 精品伊人久久大线蕉色首页| 93在线视频精品免费观看| 欧美牲交a欧美牲交| 国产伦理精品不卡| 四季av中文字幕| 精品国产户外野外| 成人av手机在线| 最近中文字幕mv在线一区二区三区四区 | 国产ts一区| 国产在线无码精品| 美女国产一区二区| 精品少妇人妻一区二区黑料社区| 亚洲精品乱码久久久久久| 精品国产www| 亚洲欧美制服丝袜| 888av在线视频| 99久久一区三区四区免费| 久久亚洲精品中文字幕蜜潮电影| www黄色日本| 99久精品国产| 欧美一级高潮片| 日韩亚洲欧美在线| 日本三级视频在线观看| 国产成人综合精品| 欧美日韩xxxx| 激情六月丁香婷婷| 91啦中文在线观看| 日韩在线视频免费播放| 精品国产99国产精品| 色呦呦在线看| 97人人干人人| 亚洲一区二区三区| 亚洲第一在线视频| 潘金莲一级淫片aaaaaaa| 久久久久久久综合日本| 国产精品黄色大片| 亚洲精品wwww| 精精国产xxx在线视频app| 高清免费日韩| 激情91久久| 欧美日韩人妻精品一区在线| 亚洲尤物在线视频观看| 性少妇videosexfreexxx片| 久久在线免费观看视频| 国产色99精品9i| 三级在线免费观看| 国产aⅴ精品一区二区三区色成熟| 九九热视频精品| 亚洲第一免费网站| 在线能看的av网址| 日韩高清在线播放| 久久精品久久综合| 日韩亚洲欧美中文字幕| 3atv一区二区三区| 欧洲性视频在线播放| 久久精品国产99精品国产亚洲性色| 亚洲黄色在线| 一本加勒比北条麻妃| 欧洲国内综合视频| 国产乱色在线观看| 97久草视频| 中文国产一区| 国产高清一区二区三区四区| 在线亚洲欧美专区二区| 暖暖日本在线观看| 成人免费视频网站| 亚洲欧美日韩国产一区| 天天舔天天操天天干| 欧美一区二区日韩| 涩涩在线视频| 亚洲一区二区三区加勒比| 国产激情视频一区二区三区欧美| 日本一级黄色大片| 国产一区二区三区在线| 国产精品99久久免费| 成人一区二区免费视频| 国产喷白浆一区二区三区| 99精品久久久久久中文字幕| 久久久久久国产三级电影| 宅男在线一区| 日韩av加勒比| 欧美午夜xxx| 国产在线1区| 欧美亚洲丝袜| 国产激情一区二区三区四区| 国产成人无码专区| 九九九热精品免费视频观看网站| 青青操综合网| 91网址在线观看精品| 欧美日韩亚洲精品一区二区三区| 天堂资源在线中文| 久久伦理网站| 国产精品99久| 亚洲天堂手机在线| 55夜色66夜色国产精品视频| 亚洲国产精品成人|