Angular如何由模板生成DOM樹的方法
Angular等現(xiàn)代Web框架極大的提高了開發(fā)效率,比如我們經(jīng)常會(huì)在開發(fā)過程中寫出類似下面的代碼:
<div> {{title}} </div> export class AppComponent { title = 'angular'; }
這種模板寫法并不是HTML原生支持的,那么Angular又是如何轉(zhuǎn)換這些代碼,并顯示成我們期望的界面呢? 首先我們來看看Angular把上述代碼編譯成什么樣子:
...省略了其他代碼 i0.ɵɵelementStart(0, "div"); i0.ɵɵtext(1, " hello angular\n"); i0.ɵɵelementEnd() ...省略了其他代碼
可以看到,Angular把我們寫的模板編譯成指令的方式,然后通過這些指令生成對(duì)應(yīng)的HTML.這個(gè)過程包含兩個(gè)步驟:
- 把模板編譯成上面的產(chǎn)物
- 執(zhí)行產(chǎn)物代碼生成HTML
本文主要圍繞步驟二進(jìn)行展開,步驟一的話可能會(huì)在后續(xù)另寫一篇進(jìn)行闡述。
觀察上面的產(chǎn)物代碼,我們不難發(fā)現(xiàn)有三個(gè)主要方法:elementStart、text、elementEnd.從它們的命名不難推測(cè),這三個(gè)方法的作用分別是開始生成標(biāo)簽、內(nèi)容賦值、閉合標(biāo)簽。下面我們來嘗試自己實(shí)現(xiàn)這幾個(gè)方法,最簡(jiǎn)單的基礎(chǔ)版本大概會(huì)是這樣:
let currentNode: Node | null = null; let currentParent: Node | null = null; function patch(host: Node | DocumentFragment, render: () => void): void { currentNode = host; render(); } function elementOpen(tagName: string): void { currentParent = currentNode; const element = document.createElement(tagName); currentParent!.appendChild(element); currentNode = element; } function text(textContent: string): void { currentNode!.textContent = textContent; } function elementEnd(tagName: string): void { currentNode = currentParent; currentParent = currentNode!.parentNode; }
然后在HTML中可以這樣使用:
<div id="container"></div> <script> function render() { elementOpen('div'); text('div content'); elementOpen('p'); text('p content'); elementEnd('p'); elementEnd('div'); } patch(document.getElementById('container'), render); </script>
上述代碼中,text方法參數(shù)都被寫固定了,實(shí)際生成的代碼可能類似于text(Comp.title)這種形式。那么既然是以變量的形式賦值,當(dāng)用戶進(jìn)行操作的時(shí)候,更新這個(gè)變量的值,豈不是又要完全重新執(zhí)行一遍patch函數(shù)么?我們知道DOM操作是耗時(shí)的,當(dāng)我們的項(xiàng)目較大時(shí),如果不采取優(yōu)化措施,勢(shì)必會(huì)影響框架性能。為此我們很容易想到的一個(gè)優(yōu)化思路,在再次執(zhí)行patch函數(shù)時(shí),如果DOM節(jié)點(diǎn)已經(jīng)存在我們就重復(fù)利用,不再去重新創(chuàng)建并插入DOM樹。基于這個(gè)思路,我們來更新一下代碼:
let currentNode: Node | null = null; let currentParent: Node | null = null; function patch(host: Node | DocumentFragment, render: () => void): void { currentNode = host; render(); } function elementOpen(tagName: string): void { currentParent = currentNode; const firstChild = (currentParent as Element).firstElementChild; if (firstChild && firstChild.tagName.toLowerCase() === tagName) { currentParent = firstChild; return; } const element = document.createElement(tagName); currentParent!.appendChild(element); currentNode = element; } function text(textContent: string): void { if (currentNode!.textContent !== textContent) { currentNode!.textContent = textContent; } } function elementEnd(tagName: string): void { currentNode = currentParent; currentParent = currentNode!.parentNode; }
本文所述代碼,只是表述Angular由模板生成dom樹的大致思路。具體的Angular做了許多優(yōu)化,而且它實(shí)現(xiàn)細(xì)節(jié)也和本文有區(qū)別。不同于現(xiàn)今較為流行的virtual DOM實(shí)現(xiàn)方式,Angular這種實(shí)現(xiàn)思路不需要單獨(dú)創(chuàng)建中間DOM對(duì)象,減少了內(nèi)存分配。對(duì)此感興趣的讀者可以自行去看Angular的實(shí)現(xiàn)。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持我們。
欄 目:JavaScript
下一篇:高性能js數(shù)組去重(12種方法,史上最全)
本文標(biāo)題:Angular如何由模板生成DOM樹的方法
本文地址:http://mengdiqiu.com.cn/a1/JavaScript/9437.html
您可能感興趣的文章
- 04-02包含javascript舍的詞條
- 01-10利用JS如何獲取form表單數(shù)據(jù)
- 01-10angularjs模態(tài)框的使用代碼實(shí)例
- 01-10詳解vue-router 動(dòng)態(tài)路由下子頁面多頁共活的解決方案
- 01-10微信小程序如何獲取地址
- 01-10如何基于JS截獲動(dòng)態(tài)代碼
- 01-10Vue 路由間跳轉(zhuǎn)和新開窗口的方式(query、params)
- 01-10Vue中axios攔截器如何單獨(dú)配置token
- 01-10如何基于JavaScript判斷圖片是否加載完成
- 01-10Angular8 實(shí)現(xiàn)table表格表頭固定效果


閱讀排行
- 1C語言 while語句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
- 3利用C語言實(shí)現(xiàn)“百馬百擔(dān)”問題方法
- 4C語言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02javascript點(diǎn)線,點(diǎn)線的代碼
- 04-02javascript潛力,javascript強(qiáng)大嗎
- 04-02javascript替換字符串,js字符串的替換
- 04-02javascript移出,js 移入移出
- 04-02包含javascript舍的詞條
- 04-02javascript并行,深入理解并行編程 豆瓣
- 04-02javascript匿名,js匿名方法
- 04-02javascript警報(bào),JavaScript警告
- 04-02javascript遮蓋,JavaScript遮蓋PC端頁面
- 04-02javascript前身,javascript的前身
隨機(jī)閱讀
- 04-02jquery與jsp,用jquery
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-10delphi制作wav文件的方法
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-10C#中split用法實(shí)例總結(jié)
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?