Angular如何由模板生成DOM樹(shù)的方法
Angular等現(xiàn)代Web框架極大的提高了開(kāi)發(fā)效率,比如我們經(jīng)常會(huì)在開(kāi)發(fā)過(guò)程中寫(xiě)出類似下面的代碼:
<div> {{title}} </div> export class AppComponent { title = 'angular'; }
這種模板寫(xiě)法并不是HTML原生支持的,那么Angular又是如何轉(zhuǎn)換這些代碼,并顯示成我們期望的界面呢? 首先我們來(lái)看看Angular把上述代碼編譯成什么樣子:
...省略了其他代碼 i0.ɵɵelementStart(0, "div"); i0.ɵɵtext(1, " hello angular\n"); i0.ɵɵelementEnd() ...省略了其他代碼
可以看到,Angular把我們寫(xiě)的模板編譯成指令的方式,然后通過(guò)這些指令生成對(duì)應(yīng)的HTML.這個(gè)過(guò)程包含兩個(gè)步驟:
- 把模板編譯成上面的產(chǎn)物
- 執(zhí)行產(chǎn)物代碼生成HTML
本文主要圍繞步驟二進(jìn)行展開(kāi),步驟一的話可能會(huì)在后續(xù)另寫(xiě)一篇進(jìn)行闡述。
觀察上面的產(chǎn)物代碼,我們不難發(fā)現(xiàn)有三個(gè)主要方法:elementStart、text、elementEnd.從它們的命名不難推測(cè),這三個(gè)方法的作用分別是開(kāi)始生成標(biāo)簽、內(nèi)容賦值、閉合標(biāo)簽。下面我們來(lái)嘗試自己實(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ù)都被寫(xiě)固定了,實(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樹(shù)?;谶@個(gè)思路,我們來(lái)更新一下代碼:
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樹(shù)的大致思路。具體的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í)有所幫助,也希望大家多多支持腳本之家。
- 詳解如何在Angular中快速定位DOM元素
- Angular2學(xué)習(xí)教程之組件中的DOM操作詳解
- 詳解angular中如何監(jiān)控dom渲染完畢
- AngularJS實(shí)現(xiàn)動(dòng)態(tài)編譯添加到dom中的方法
- AngularJS學(xué)習(xí)筆記之TodoMVC的分析
- Angular.JS通過(guò)指令操作DOM的方法
- AngularJS中的DOM操作用法分析
- AngularJS實(shí)現(xiàn)DOM元素的顯示與隱藏功能
- Angular4學(xué)習(xí)教程之DOM屬性綁定詳解
- 詳解Angular如何正確的操作DOM
- Angular2進(jìn)階之如何避免Dom誤區(qū)
相關(guān)文章
對(duì)angularjs框架下controller間的傳值方法詳解
今天小編就為大家分享一篇對(duì)angularjs框架下controller間的傳值方法詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-10-10理解Angular的providers給Http添加默認(rèn)headers
本篇文章主要介紹了理解Angular的providers給Http添加默認(rèn)headers,具有一定的參考價(jià)值,有興趣的同學(xué)可以了解一下2017-07-07angularjs指令中的compile與link函數(shù)詳解
這篇文章主要介紹了angularjs指令中的compile與link函數(shù)詳解,本文同時(shí)訴大家complie,pre-link,post-link的用法與區(qū)別等內(nèi)容,需要的朋友可以參考下2014-12-12Angular2學(xué)習(xí)筆記——詳解路由器模型(Router)
這篇文章主要介紹了Angular2學(xué)習(xí)筆記——詳解路由器模型(Router),非常具有實(shí)用價(jià)值,需要的朋友可以參考下。2016-12-12Angular ui.bootstrap.pagination分頁(yè)
這篇文章主要為大家詳細(xì)介紹了Angular ui.bootstrap.pagination 分頁(yè)的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01AngularJs ng-repeat 嵌套如何獲取外層$index
這篇文章主要介紹了AngularJs ng-repeat 嵌套如何獲取外層$index的相關(guān)資料,需要的朋友可以參考下2016-09-09AngularJS 驗(yàn)證碼60秒倒計(jì)時(shí)功能的實(shí)現(xiàn)
最近在做AngularJS 項(xiàng)目,這是寫(xiě)的一個(gè)60秒倒計(jì)時(shí)功能,下面小編給大家介紹AngularJS 驗(yàn)證碼60秒倒計(jì)時(shí)功能的實(shí)現(xiàn),需要的朋友參考下吧2017-06-06