作為「為大型前端專案」而設計的前端框架,Angular 其實有許多值得參考和學習的設計,本系列主要用於研究這些設計和功能的實現原理。本文主要圍繞 Angular 中與檢視有關的一些定義進行介紹。
Angular 版本可在不同的平臺上執行:在瀏覽器中、在行動平臺上或在 Web Worker 中。因此,需要特定級別的抽象來介於平臺特定的 API 和框架介面之間。【相關教學推薦:《》】
Angular 中通過抽象封裝了不同平臺的差異,並以下列參照型別的形式出現:ElementRef
,TemplateRef
,ViewRef
,ComponentRef
和ViewContainerRef
。
各抽象類檢視定義
在閱讀原始碼的時候,如果不清楚這些定義之間的區別,很容易搞混淆。所以,這裡我們先來理解下它們之間的區別。
元素 ElementRef
ElementRef
是最基本的抽象。如果觀察它的類結構,可以看到它僅包含與其關聯的本地元素:
export class ElementRef<T = any> { // 基礎原生元素 // 如果不支援直接存取原生元素(例如當應用程式在 Web Worker 中執行時),則為 null public nativeElement: T; constructor(nativeElement: T) { this.nativeElement = nativeElement; } ... }
該 API 可用於直接存取本地 DOM 元素,可以比作document.getElementById('myId')
。但 Angular 並不鼓勵直接使用,儘可能使用 Angular 提供的模板和資料繫結。
模板 TemplateRef
在 Angular 中,模板用來定義要如何在 HTML 中渲染元件檢視的程式碼。
模板通過@Component()
裝飾器與元件類類關聯起來。模板程式碼可以作為template
屬性的值用內聯的方式提供,也可以通過 templateUrl
屬性連結到一個獨立的 HTML 檔案。
用TemplateRef
物件表示的其它模板用來定義一些備用檢視或內嵌檢視,它們可以來自多個不同的元件。TemplateRef
是一組 DOM 元素(ElementRef
),可在整個應用程式的檢視中重複使用:
export abstract class TemplateRef<C> { // 此嵌入檢視的父檢視中的 anchor 元素 abstract get elementRef(): ElementRef; // 基於此模板範例化嵌入式檢視,並將其附加到檢視容器 abstract createEmbeddedView(context: C): EmbeddedViewRef<C>; ... }
就其本身而言,TemplateRef
類是一個簡單的類,僅包括:
elementRef
屬性:擁有對其宿主元素的參照createEmbeddedView
方法:它允許我們建立檢視並將其參照作為ViewRef
返回。模板會把純 HTML 和 Angular 的資料繫結語法、指令和模板表示式組合起來。Angular 的元素會插入或計算那些值,以便在頁面顯示出來之前修改 HTML 元素。
Angular 中的檢視
在 Angular 中,檢視是可顯示元素的最小分組單位,它們會被同時建立和銷燬。Angular 哲學鼓勵開發人員將 UI 視為檢視的組合(而不是獨立的 html 標籤樹)。
元件(component
) 類及其關聯的模板(template
)定義了一個檢視。具體實現上,檢視由一個與該元件相關的ViewRef
範例表示。
ViewRef
ViewRef
表示一個 Angular 檢視:
export declare abstract class ViewRef extends ChangeDetectorRef { // 銷燬該檢視以及與之關聯的所有資料結構 abstract get destroyed(): boolean; // 報告此檢視是否已被銷燬 abstract destroy(): void; // 生命週期掛鉤,為檢視提供其他開發人員定義的清理功能 abstract onDestroy(callback: Function): any; }
其中,ChangeDetectorRef
提供更改檢測功能的基礎類別,用於更改檢測樹收集所有要檢查更改的檢視:
export declare abstract class ChangeDetectorRef { // 當輸入已更改或檢視中觸發了事件時,通常會將元件標記為髒(需要重新渲染) // 呼叫此方法以確保即使沒有發生這些觸發器,也要檢查元件 abstract checkNoChanges(): void; // 從變更檢測樹中分離該檢視。在重新連線分離檢視之前,不會對其進行檢查。 // 與 detectChanges() 結合使用可實現本地變更檢測檢查 abstract detach(): void; // 檢查此檢視及其子級,與 detach() 結合使用可實現本地更改檢測檢查 abstract detectChanges(): void; // 檢查變更檢測器及其子級,如果檢測到任何變更,則丟擲該異常 abstract markForCheck(): void; // 將先前分離的檢視重新附加到變更檢測樹 // 預設情況下,檢視將附加到樹上 abstract reattach(): void; }
兩種型別的檢視
Angular 支援兩種型別的檢視:
(1) 連結到模板(template)的嵌入式檢視(embeddedView)。
嵌入式檢視表示檢視容器中的 Angular 檢視。模板只是儲存檢視的藍圖,可以使用上述的createEmbeddedView
方法從模板範例化檢視。
(2) 連結到元件(component)的宿主檢視(hostView)。
直屬於某個元件的檢視叫做宿主檢視。
宿主檢視是在動態範例化元件時建立的,可以使用ComponentFactoryResolver
動態建立範例化一個元件。在 Angular 中,每個元件都繫結到特定的注入器範例,因此在建立元件時我們將傳遞當前的注入器範例。
檢視中各個元素的屬性可以動態修改以響應使用者的操作,而這些元素的結構(數量或順序)則不能。你可以通過在它們的檢視容器(ViewContainer
)中插入、移動或移除內嵌檢視來修改這些元素的結構。
ViewContainerRef
ViewContainerRef
是可以將一個或多個檢視附著到元件中的容器:
export declare abstract class ViewContainerRef { // 錨元素,用於指定此容器在包含檢視中的位置 // 每個檢視容器只能有一個錨元素,每個錨元素只能有一個檢視容器 abstract get element(): ElementRef; // 此檢視容器的 DI abstract get injector(): Injector; // 此容器當前附加了多少檢視 abstract get length(): number; // 銷燬此容器中的所有檢視 abstract clear(): void; // 範例化單個元件,並將其宿主檢視插入此容器 abstract createComponent<C>(componentFactory: ComponentFactory<C>, index?: number, injector?: Injector, projectableNodes?: any[][], ngModule?: NgModuleRef<any>): ComponentRef<C>; // 範例化一個嵌入式檢視並將其插入 abstract createEmbeddedView<C>(templateRef: TemplateRef<C>, context?: C, index?: number): EmbeddedViewRef<C>; // 從此容器分離檢視而不銷燬它 abstract detach(index?: number): ViewRef | null; // 從此容器檢索檢視 abstract get(index: number): ViewRef | null; // 返回當前容器內檢視的索引 abstract indexOf(viewRef: ViewRef): number; // 將檢視移動到此容器中的新位置 abstract insert(viewRef: ViewRef, index?: number): ViewRef; abstract move(viewRef: ViewRef, currentIndex: number): ViewRef; // 銷燬附加到此容器的檢視 abstract remove(index?: number): void; }
任何 DOM 元素都可以用作檢視容器,Angular 不會在元素內插入檢視,而是將它們附加到繫結到ViewContainer
的元素之後。
通常,標記
ng-container
元素是標記應建立ViewContainer
的位置的最佳選擇。它作為註釋呈現,因此不會在 DOM 中引入多餘的 HTML 元素。
通過ViewContainerRef
,可以用createComponent()
方法範例化元件時建立宿主檢視,也可以用 createEmbeddedView()
方法範例化TemplateRef
時建立內嵌檢視。
檢視容器的範例還可以包含其它檢視容器,以建立層次化檢視(檢視樹)。
檢視樹(View hierarchy)
在 Angular 中,通常會把檢視組織成一些檢視樹(view hierarchies)。檢視樹是一棵相關檢視的樹,它們可以作為一個整體行動,是 Angular 變更檢測的關鍵部件之一。
檢視樹的根檢視就是元件的宿主檢視。宿主檢視可以是內嵌檢視樹的根,它被收集到了宿主元件上的一個檢視容器(ViewContainerRef
)中。當使用者在應用中導航時(比如使用路由器),檢視樹可以動態載入或解除安裝。
檢視樹和元件樹並不是一一對應的:
NgModule
中,也可能屬於其它NgModule
元件、模板、檢視與模組
在 Angular 中,可以通過元件的配套模板來定義其檢視。模板就是一種 HTML,它會告訴 Angular 如何渲染該元件。
檢視通常會分層次進行組織,讓你能以 UI 分割區或頁面為單位進行修改、顯示或隱藏。與元件直接關聯的模板會定義該元件的宿主檢視。該元件還可以定義一個帶層次結構的檢視,它包含一些內嵌的檢視作為其它元件的宿主。
帶層次結構的檢視可以包含同一模組(NgModule
)中元件的檢視,也可以(而且經常會)包含其它模組中定義的元件的檢視。
總結
本文簡單介紹了 Angular 中元素、檢視、模板、元件中與檢視相關的一些定義,包括ElementRef
,TemplateRef
,ViewRef
,ComponentRef
和ViewContainerRef
。
其中,檢視是 Angular 中應用程式 UI 的基本構建塊,它是一起建立和銷燬的最小元素組。
ViewContainerRef
主要用於建立和管理內嵌檢視或元件檢視。元件可以通過設定模板來定義檢視,與元件直接關聯的模板會定義該元件的宿主檢視,同時元件還可以包括內嵌檢視。
更多程式設計相關知識,請存取:!!
以上就是聊聊Angular中與檢視有關的一些定義的詳細內容,更多請關注TW511.COM其它相關文章!