日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

使用ViewContainerRef探索Angular DOM操作技术

發(fā)布時間:2023/11/29 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用ViewContainerRef探索Angular DOM操作技术 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

每當我閱讀中遇到,關于Angular中使用DOM的內(nèi)容時,總會看到一個或幾個這樣的類:ElementRef,TemplateRef,ViewContainerRef等等。 不幸的是,雖然其中的一些被Angular文檔或相關文章所講述,但是我還沒有找到完整的描述以及這些它們是如何工作的。

如果你來自angular.js世界,那么你知道操縱DOM是相當容易的。Angular注入DOM elementRef到構(gòu)造函數(shù)中,你可以查詢組件模板中的任何節(jié)點,添加或刪除子節(jié)點,修改樣式等。但是,這種方法有一個主要的缺點 - 它緊緊地綁定到瀏覽器平臺。

新的Angular版本運行在不同的平臺上 - 瀏覽器,移動平臺等。 因此,站在平臺特定的API和框架接口之間需要抽象層次。Angular中,這些抽象成為以下引用類型的形式:ElementRef,TemplateRef,ViewRef,ComponentRef和ViewContainerRef。 在本文中,我們將詳細介紹每種引用類型,并展示如何使用它們來操作DOM。

@ViewChild

在我們探索DOM抽象之前,讓我們了解如何在組件/指令類中訪問這些抽象。 Angular提供了一種稱為DOM查詢的機制。 它以@ViewChild和@ViewChildren裝飾器的形式出現(xiàn)。 它們的行為相同,只有前者返回一個引用,后者則返回多個引用作為QueryList對象。 在這篇文章的例子中,我將主要使用ViewChild裝飾器。

通常,這些裝飾器與模板引用變量配對使用。 模板引用變量只是對模板中的DOM元素的命名引用。 您可以將其視為與html元素的id屬性類似的東西。 用模板引用標記DOM元素,然后使用ViewChild裝飾器在類中查詢它。 這里是基本的例子:

@Component({selector: 'sample',template: `<span #tref>I am span</span>` }) export class SampleComponent implements AfterViewInit {@ViewChild("tref", {read: ElementRef}) tref: ElementRef;ngAfterViewInit(): void {// outputs `I am span`console.log(this.tref.nativeElement.textContent);} }

ViewChild裝飾器的基本語法如下:

@ViewChild([reference from template], {read: [reference type]});

在這個例子中,你可以看到我在html中指定了tref作為模板引用名,并且接收到與這個元素相關的ElementRef。 讀取的第二個參數(shù)并不總是必需的,因為Angular可以通過DOM元素的類型來推斷引用類型。 例如,如果它是一個簡單的HTML元素(如span),那么angular將返回ElementRef。 如果它是一個模板元素,它將返回TemplateRef。不過一些引用,如ViewContainerRef不能被推斷,并且必須在讀參數(shù)中特別要求。 其他的,像ViewRef不能從DOM返回,必須手動構(gòu)造。

ElementRef

這是最基本的抽象。 如果你觀察它的類結(jié)構(gòu),你會發(fā)現(xiàn)它只保存了它所關聯(lián)的本地元素。 對于訪問本地DOM元素非常有用,我們可以在這里看到:

// outputs `I am span` console.log(this.tref.nativeElement.textContent);

不過,Angular團隊不鼓勵這種用法。 這不僅會帶來安全風險,還會在應用程序和渲染層之間造成緊密耦合,這使得在多個平臺上運行應用程序變得困難。 我相信這不是對nativeElement的訪問,而是打破了抽象,而是像textContent一樣使用特定的DOM API。 但是后面你會看到,在Angular中實現(xiàn)的DOM操作心智模型幾乎不需要這樣一個較低級別的訪問。

可以使用ViewChild裝飾器為任何DOM元素返回ElementRef。 但是,由于所有組件都駐留在自定義DOM元素中,并且所有指令都應用于DOM元素,因此組件和指令類可以通過DI機制獲取與其主機元素關聯(lián)的ElementRef實例:

@Component({selector: 'sample',... export class SampleComponent{constructor(private hostElement: ElementRef) {//outputs <sample>...</sample>console.log(this.hostElement.nativeElement.outerHTML);}

因此,雖然組件可以通過DI訪問其主機元素,但ViewChild裝飾器通常用于在其視圖(模板)中獲取對DOM元素的引用。 反之亦然,指令沒有視圖,他們通常直接與他們所附的元素。

模板的概念應該是大多數(shù)Web開發(fā)人員熟悉的。 這是一組DOM元素,在整個應用程序的視圖中被重用。 在HTML5標準引入了模板標簽之前,大多數(shù)模板都被包含在script標簽中。

<script id="tpl" type="text/template"><span>I am span in template</span> </script>

這種方法當然有許多缺點,如語義和手動創(chuàng)建DOM模型的必要性。 使用模板標簽瀏覽器解析HTML并創(chuàng)建DOM樹,但不呈現(xiàn)它。 然后可以通過內(nèi)容屬性訪問:

<script>let tpl = document.querySelector('#tpl');let container = document.querySelector('.insert-after-me');insertAfter(container, tpl.content); </script> <div class="insert-after-me"></div> <ng-template id="tpl"><span>I am span in template</span> </ng-template>

Angular支持這種方法,并實現(xiàn)TemplateRef類來處理模板。 以下是如何使用它:

@Component({selector: 'sample',template: `<ng-template #tpl><span>I am span in template</span></ng-template>` }) export class SampleComponent implements AfterViewInit {@ViewChild("tpl") tpl: TemplateRef<any>;ngAfterViewInit() {let elementRef = this.tpl.elementRef;// outputs `template bindings={}`console.log(elementRef.nativeElement.textContent);} }

該框架從DOM中刪除模板元素,并在其位置插入注釋。 這是呈現(xiàn)時的樣子:

<sample><!--template bindings={}--> </sample>

TemplateRef類本身是一個簡單的類。 它的elementRef屬性擁有對其宿主元素的引用,并具有一個方法createEmbeddedView。 這個方法非常有用,因為它允許我們創(chuàng)建一個視圖并以ViewRef的形式返回一個引用。

ViewRef

這種抽象表示Angular視圖。 在Angular世界中,View是應用程序UI的基本構(gòu)建塊。 它是創(chuàng)造和消滅的最小的元素分組。 Angular哲學鼓勵開發(fā)人員將UI視為Views的組合,而不是將其視為獨立的HTML標簽。

Angular支持兩種類型的視圖:

  • 嵌入視圖鏈接到模板
  • 鏈接到組件的主機視圖

創(chuàng)建嵌入的視圖

一個模板只是一個視圖的藍圖。 一個視圖可以使用前面提到的createEmbeddedView方法從模板實例化,如下所示:

ngAfterViewInit() {let view = this.tpl.createEmbeddedView(null); }

創(chuàng)建宿主視圖

宿主視圖是在組件動態(tài)實例化時創(chuàng)建的。 可以使用ComponentFactoryResolver動態(tài)創(chuàng)建一個組件:

constructor(private injector: Injector,private r: ComponentFactoryResolver) {let factory = this.r.resolveComponentFactory(ColorComponent);let componentRef = factory.create(injector);let view = componentRef.hostView; }

在Angular中,每個組件都綁定到一個注入器的特定實例,所以我們在創(chuàng)建組件時傳遞當前的注入器實例。 此外,不要忘記,動態(tài)實例化的組件必須添加到模塊或主機組件的EntryComponents。

所以,我們已經(jīng)看到如何創(chuàng)建嵌入和宿主視圖。 一旦創(chuàng)建了視圖,就可以使用ViewContainer將其插入到DOM中。 下一節(jié)將探討其功能。

ViewContainerRef

表示可以附加一個或多個視圖的容器。

首先要提到的是,任何DOM元素都可以用作視圖容器。有趣的是,Angular不在元素內(nèi)插入視圖,而是在綁定到ViewContainer的元素之后附加它們。 這與路由器插座如何插入組件類似。

通常,標記應該創(chuàng)建ViewContainer的地方的好候選者是ng-container元素。 它被渲染為一個注釋,所以它不會在DOM中引入多余的html元素。 以下是在組件模板的特定位置創(chuàng)建ViewContainer的示例:

@Component({selector: 'sample',template: `<span>I am first span</span><ng-container #vc></ng-container><span>I am last span</span>` }) export class SampleComponent implements AfterViewInit {@ViewChild("vc", {read: ViewContainerRef}) vc: ViewContainerRef;ngAfterViewInit(): void {// outputs `template bindings={}`console.log(this.vc.element.nativeElement.textContent);} }

就像其他DOM抽象一樣,ViewContainer綁定到通過元素屬性訪問的特定DOM元素。 在這個例子中,ng-container元素被綁定為注釋的示例中,輸出為template bindings = {}。

Manipulating views

ViewContainer為操作視圖提供了一個方便的API:

class ViewContainerRef {...clear() : voidinsert(viewRef: ViewRef, index?: number) : ViewRefget(index: number) : ViewRefindexOf(viewRef: ViewRef) : numberdetach(index?: number) : ViewRefmove(viewRef: ViewRef, currentIndex: number) : ViewRef }

我們之前已經(jīng)看到,如何從模板和組件手動創(chuàng)建兩種類型的視圖。 一旦我們有了一個視圖,我們可以使用插入方法將其插入到DOM中。 所以,下面是從模板中創(chuàng)建一個嵌入式視圖并將其插入到由ng-container元素標記的特定位置的示例:

@Component({selector: 'sample',template: `<span>I am first span</span><ng-container #vc></ng-container><span>I am last span</span><ng-template #tpl><span>I am span in template</span></ng-template>` }) export class SampleComponent implements AfterViewInit {@ViewChild("vc", {read: ViewContainerRef}) vc: ViewContainerRef;@ViewChild("tpl") tpl: TemplateRef<any>;ngAfterViewInit() {let view = this.tpl.createEmbeddedView(null);this.vc.insert(view);} }

通過這個實現(xiàn),生成的html看起來像這樣:

<sample><span>I am first span</span><!--template bindings={}--><span>I am span in template</span><span>I am last span</span><!--template bindings={}--> </sample>

要從DOM中刪除視圖,我們可以使用detach方法。 所有其他方法都是自解釋性的,可用于通過索引獲取對視圖的引用,將視圖移至其他位置或從容器中移除所有視圖。

Creating Views

ViewContainer還提供API來自動創(chuàng)建視圖:

class ViewContainerRef {element: ElementReflength: numbercreateComponent(componentFactory...): ComponentRef<C>createEmbeddedView(templateRef...): EmbeddedViewRef<C>... }

這些都是我們上面手動完成的簡單包裝。 他們從模板或組件創(chuàng)建一個視圖,并將其插入到指定位置。

ngTemplateOutlet and ngComponentOutlet

ngTemplateOutlet

這個將一個DOM元素標記為ViewContainer,并在其中插入一個由模板創(chuàng)建的嵌入視圖,而不需要在組件類中明確地做到這一點。 這意味著上面我們創(chuàng)建視圖并將其插入到#vc DOM元素的示例可以像這樣重寫:

@Component({selector: 'sample',template: `<span>I am first span</span><ng-container [ngTemplateOutlet]="tpl"></ng-container><span>I am last span</span><ng-template #tpl><span>I am span in template</span></ng-template>` }) export class SampleComponent {}

正如你所看到的,我們不使用任何視圖實例化組件類中的代碼。 非常便利。

ngComponentOutlet

該指令類似于ngTemplateOutlet,不同之處在于它創(chuàng)建一個宿主視圖(實例化一個組件),而不是嵌入視圖。 你可以像這樣使用它:

<ng-container *ngComponentOutlet="ColorComponent"></ng-container>

總結(jié)

現(xiàn)在,所有這些信息似乎都可以被消化,但實際上這些信息是非常連貫的,并且通過視圖來顯示操縱DOM的清晰模型。 通過使用ViewChild查詢和模板變量引用,您可以獲得對Angular DOM抽象的引用。 圍繞DOM元素的最簡單的包裝是ElementRef。 對于具有TemplateRef的模板,您可以創(chuàng)建嵌入式視圖。 主機視圖可以在使用ComponentFactoryResolver創(chuàng)建的componentRef上訪問。 視圖可以用ViewContainerRef來操作。 有兩個使自動手動過程的指令:ngTemplateOutlet - 用于嵌入視圖,ngComponentOutlet用于宿主視圖(動態(tài)組件)。

總結(jié)

以上是生活随笔為你收集整理的使用ViewContainerRef探索Angular DOM操作技术的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。