Angular 內容投影 content projection 關於選擇器問題的單步除錯
問題描述
我定義了一個能夠允許消費者 Component 將其自定義內容通過 content projection
投射進來的 Component:
import { Component } from '@angular/core'; @Component({ selector: 'app-zippy-basic', template: ` Default: <ng-content></ng-content> Question: <ng-content select="[question]"></ng-content> ` }) export class ZippyBasicComponent {}
其中包含 default
和 question
兩個區域。
對於 question 區域而言,只有在消費 Component 提供的內容,滿足第 10 行指定的選擇器時,該內容才能被投影到 app-zippy-basic
內部。
我的消費程式碼如下:
<app-zippy-basic>
<p #question>
帶了問號的 p 節點
</p>
<p>普通 p 節點</p>
</app-zippy-basic>
我期望的結果:
- 普通 p 節點,出現在 default 區域;
- 帶了問號的 p 節點,出現在 question 區域。
實際測試結果:question 區域為空。
問題分析
根據 Angular 官網的定義,select="[question]" 的語法含義是,將消費 Component 中具有 question
的 attribute
的 dom 節點,投射到 app-zippy-basic
中。因此,第 23 行中的 #
應該去掉,這樣才能產生一個具有 question
屬性的 p 節點:
去掉之後,p 節點果然按照我們期望的那樣,顯示在 default
區域了:
我們再來通過單步除錯的方式,找到帶有 question
屬性的 p 節點是如何被選擇以及投射的。
Angular 框架內部維護了一個叫做 LView
Logic View
的資料結構,這是一個數組:
LView
的內容:
其中索引為 21 的陣列元素,rawSlotValue
,存放的就是需要被投影到 question 區域,帶有 question 屬性的 p 節點。
總結
如果元件包含一個沒有 select 屬性的 ng-content
元素,則該例項會接收與任何其他 ng-content
元素都不匹配的所有投影元件。
邏輯檢視 (LView) 表示模板 (TView) 的例項。 我們使用邏輯
這個詞來強調開發人員如何從邏輯角度看待應用程式。 ParentComponent 包含一個 ChildComponent。 從邏輯的角度來看,我們認為 ParentComponent 包含 ChildComponent,因此稱為邏輯
。 邏輯一詞與渲染樹的最終概念形成對比。