一文了解 ng-template, ng-content, ng-container, 和 *ngTemplateOutlet的区别
原文
今天當我在做 Angular 開發時,一個知識點引起了我的注意:
在檢查 DOM 時,我看到 ngcontent 被 Angular 應用于元素。 嗯……如果它們包含了最終 DOM 中的元素,那么 <ng-container> 有什么用? 當時我對 <ng-container> 和 <ng-content> 的區別感到困惑。
在尋求知道我的問題的答案的過程中,我發現了 <ng-template> 的概念。 令我驚訝的是,還有另一個容易混淆的概念: *ngTemplateOutlet。 我開始了我的旅程,尋求對兩個概念的澄清,但現在我有四個,聽起來幾乎一樣!
你遇到過這種情況嗎? 如果是,那么您來對地方了。 因此,事不宜遲,讓我們一一介紹。
1. <ng-template>
顧名思義,<ng-template> 是一個模板元素,Angular 與結構指令(*ngIf、*ngFor、[ngSwitch] 和自定義指令)一起使用。
這些模板元素僅在存在結構指令時才起作用。 Angular 將宿主元素(指令所應用到的元素)包裝在 <ng-template> 中,并通過用診斷注釋(diagnostic comments)替換它來使用完成的 DOM 中的 <ng-template>。
考慮一個簡單的 *ngIf 示例:
上面顯示的是 *ngIf 的 Angular 解釋,也就是解除語法糖之后的實際代碼。 Angular 將應用指令的宿主元素放在 <ng-template> 中,并保持宿主原樣。 最終的 DOM 類似于我們在本文開頭看到的:
2. <ng-container>
我們很多人編寫這段代碼的原因是無法在 Angular 中的單個宿主元素上使用多個結構指令。 現在這段代碼工作正常,但如果 item.id 是一個可能不需要的虛假值,它會在 DOM 中引入幾個額外的空 <div> 。
人們可能不會關心像這樣的簡單示例,但是對于具有復雜 DOM(顯示數萬個數據)的大型應用程序,這可能會變得很麻煩,因為元素可能具有附加到它們的偵聽器,這些偵聽器仍然存在于 DOM 監聽事件。
更糟糕的是應用樣式 (CSS) 必須執行的嵌套級別!
不用擔心,我們有 <ng-container> 來救援!
Angular <ng-container> 是一個不會干擾樣式或布局的分組元素,因為 Angular 不會將它放在 DOM 中。
使用 ng-container 重寫。
可以理解成把 div 標簽放置到 ng-container 這個虛無的容器里,當 div 的 *ngIf 指令布爾值為 false 時,虛無的容器連同里面的 div 標簽壓根就不會生成。
最后渲染出的 HTML 代碼里,沒有多余的空 div 標簽了:
最佳實踐:當我們只想應用多個結構指令而不在我們的 DOM 中引入任何額外元素時,我們應該使用 <ng-container>。
3. <ng-content>
它們用于創建可配置組件。 這意味著可以根據用戶的需要配置組件。 這就是眾所周知的內容投影: Content Projection. 已發布庫中使用的組件使用 <ng-content> 使自己可配置。
考慮一個簡單的 <project-content> 組件,下圖是其本身的 HTML 定義:
顯然,footer 區域允許動態配置內容。
下圖展示了如何為 footer 區域動態注入自定義 footer 內容。這種用法稱為單一投射。
<project-content> 組件的開始和結束標記中傳遞的 HTML 內容就是要投影的內容。 這就是我們所說的內容投影。被投影的內容將在提供內容投影功能組件內的 <ng-content> 內呈現。
這允許 <project-content> 組件的使用者在組件內傳遞任何自定義頁腳,并準確控制他們希望如何呈現它。
Multiple Projections
如果您可以決定哪些內容應該放在什么地方呢? 除了將每個內容投影到單個 <ng-content> 中之外,您還可以使用 <ng-content> 的 select 屬性控制內容的投影方式。 它需要一個元素選擇器來決定在特定的 <ng-content> 中投射哪些內容。
就是這樣:
我們修改了 <project-content> 定義以執行多內容投影。 select 屬性選擇將在特定 中呈現的內容類型。 這里我們首先選擇渲染標題 h1 元素。 如果投影內容沒有 h1 元素,它將不會呈現任何內容。 同樣,第二個選擇查找 div。 其余內容在最后一個 <ng-content> 中呈現,沒有選擇。
如何消費這個帶有 select 屬性的,允許多重投射的組件?方法如下所示:
4. *ngTemplateOutlet
*ngTemplateOutlet 用于兩種場景:
- 在視圖的各個部分插入一個通用模板,而不考慮循環或條件
- 制作高度配置的組件。
模板重用
考慮一個視圖,您必須在多個位置插入模板。 例如,要放置在網站中的公司徽標。 我們可以通過為徽標編寫一次模板并在視圖中的任何地方重用它來實現它。
以下是代碼片段:
如您所見,我們只編寫了一次徽標模板,并在同一頁面上使用一行代碼將其使用了 3 次.
Customizable components
*ngTemplateOutlet 的第二個用例是高度定制的組件。 考慮我們之前的 <project-content> 組件示例,并進行了一些修改:
以上是 <project-content>組件的修改版本,它接受三個輸入屬性 —— headerTemplate、bodyTemplate、footerTemplate。 以下是 project-content.ts 的片段:
模板文件里使用到的 input 屬性,headerTemplate,bodyTemplate 和 footerTemplate 屬性定義在 Component 文件里。
我們在這里試圖實現的是顯示從 <project-content> 的父組件接收到的頁眉、正文和頁腳。 如果未提供其中任何一個,我們的組件將在其位置顯示默認模板。 因此,創建了一個高度定制的組件。
要使用我們最近修改的組件:
這就是我們將模板引用傳遞給我們的組件的方式。 如果其中任何一個未通過,則組件將呈現默認模板。
ng-content vs. *ngTemplateOutlet
它們都可以幫助我們實現高度定制化的組件,但選擇哪個以及何時選擇?
可以清楚地看到,如果沒有提供, *ngTemplateOutlet 為我們提供了更多顯示默認模板的能力。
這不是 ng-content 的情況。 它按原樣呈現內容。 您最多可以在 select 屬性的幫助下拆分內容并在視圖的不同位置呈現它們。 您不能有條件地呈現 ng-content 中的內容。 您必須顯示從父級收到的內容,而無法根據內容做出決定。
但是,在兩者中進行選擇完全取決于您的用例。 至少現在我們的武器庫中有一個新武器 *ngTemplateOutlet,除了 ng-content 的功能外,它還提供了對內容的更多控制。
更多Jerry的原創文章,盡在:“汪子熙”:
總結
以上是生活随笔為你收集整理的一文了解 ng-template, ng-content, ng-container, 和 *ngTemplateOutlet的区别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 天科合达与英飞凌签订碳化硅材料长期供货协
- 下一篇: 星链宣布普通用户不再达量降速,但其实网速