聊聊Angular中與檢視有關的一些定義

2022-03-01 13:00:41
本篇文章給大家聊聊中的檢視抽象定義,圍繞 Angular 中與檢視有關的一些定義進行介紹,希望對大家有所幫助!

作為「為大型前端專案」而設計的前端框架,Angular 其實有許多值得參考和學習的設計,本系列主要用於研究這些設計和功能的實現原理。本文主要圍繞 Angular 中與檢視有關的一些定義進行介紹。

Angular 中的檢視抽象

Angular 版本可在不同的平臺上執行:在瀏覽器中、在行動平臺上或在 Web Worker 中。因此,需要特定級別的抽象來介於平臺特定的 API 和框架介面之間。【相關教學推薦:《》】

Angular 中通過抽象封裝了不同平臺的差異,並以下列參照型別的形式出現:ElementRefTemplateRefViewRefComponentRefViewContainerRef

各抽象類檢視定義

在閱讀原始碼的時候,如果不清楚這些定義之間的區別,很容易搞混淆。所以,這裡我們先來理解下它們之間的區別。

元素 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 分割區或頁面為單位進行修改、顯示或隱藏。與元件直接關聯的模板會定義該元件的宿主檢視。該元件還可以定義一個帶層次結構的檢視,它包含一些內嵌的檢視作為其它元件的宿主。

1.gif

帶層次結構的檢視可以包含同一模組(NgModule)中元件的檢視,也可以(而且經常會)包含其它模組中定義的元件的檢視。

總結

本文簡單介紹了 Angular 中元素、檢視、模板、元件中與檢視相關的一些定義,包括ElementRefTemplateRefViewRefComponentRefViewContainerRef

其中,檢視是 Angular 中應用程式 UI 的基本構建塊,它是一起建立和銷燬的最小元素組。

ViewContainerRef主要用於建立和管理內嵌檢視或元件檢視。元件可以通過設定模板來定義檢視,與元件直接關聯的模板會定義該元件的宿主檢視,同時元件還可以包括內嵌檢視。

更多程式設計相關知識,請存取:!!

以上就是聊聊Angular中與檢視有關的一些定義的詳細內容,更多請關注TW511.COM其它相關文章!