溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Angular怎樣由模板生成DOM樹

發(fā)布時間:2021-02-02 10:11:59 來源:億速云 閱讀:210 作者:小新 欄目:web開發(fā)

這篇文章將為大家詳細講解有關Angular怎樣由模板生成DOM樹,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

Angular等現(xiàn)代Web框架極大的提高了開發(fā)效率,比如我們經(jīng)常會在開發(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把我們寫的模板編譯成指令的方式,然后通過這些指令生成對應的HTML.這個過程包含兩個步驟:

  1. 把模板編譯成上面的產(chǎn)物

  2. 執(zhí)行產(chǎn)物代碼生成HTML

本文主要圍繞步驟二進行展開,步驟一的話可能會在后續(xù)另寫一篇進行闡述。

觀察上面的產(chǎn)物代碼,我們不難發(fā)現(xiàn)有三個主要方法:elementStart、text、elementEnd.從它們的命名不難推測,這三個方法的作用分別是開始生成標簽、內(nèi)容賦值、閉合標簽。下面我們來嘗試自己實現(xiàn)這幾個方法,最簡單的基礎版本大概會是這樣:

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ù)都被寫固定了,實際生成的代碼可能類似于text(Comp.title)這種形式。那么既然是以變量的形式賦值,當用戶進行操作的時候,更新這個變量的值,豈不是又要完全重新執(zhí)行一遍patch函數(shù)么?我們知道DOM操作是耗時的,當我們的項目較大時,如果不采取優(yōu)化措施,勢必會影響框架性能。為此我們很容易想到的一個優(yōu)化思路,在再次執(zhí)行patch函數(shù)時,如果DOM節(jié)點已經(jīng)存在我們就重復利用,不再去重新創(chuàng)建并插入DOM樹。基于這個思路,我們來更新一下代碼:

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)化,而且它實現(xiàn)細節(jié)也和本文有區(qū)別。不同于現(xiàn)今較為流行的virtual DOM實現(xiàn)方式,Angular這種實現(xiàn)思路不需要單獨創(chuàng)建中間DOM對象,減少了內(nèi)存分配。對此感興趣的讀者可以自行去看Angular的實現(xiàn)。

關于“Angular怎樣由模板生成DOM樹”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI