使用ViewContainerRef探索Angular DOM操作技術

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

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

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

@ViewChild

在我們探索DOM抽象之前,讓我們了解如何在組件/指令類中訪問這些抽象。 Angular提供了一種稱為DOM查詢的機制。 它以@ViewChild和@ViewChildren裝飾器的形式出現。 它們的行為相同,只有前者返回一個引用,后者則返回多個引用作為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。 讀取的第二個參數并不總是必需的,因為Angular可以通過DOM元素的類型來推斷引用類型。 例如,如果它是一個簡單的HTML元素(如span),那么angular將返回ElementRef。 如果它是一個模板元素,它將返回TemplateRef。不過一些引用,如ViewContainerRef不能被推斷,并且必須在讀參數中特別要求。 其他的,像ViewRef不能從DOM返回,必須手動構造。

ElementRef

這是最基本的抽象。 如果你觀察它的類結構,你會發現它只保存了它所關聯的本地元素。 對于訪問本地DOM元素非常有用,我們可以在這里看到:

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

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

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

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

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

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

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

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

<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支持這種方法,并實現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中刪除模板元素,并在其位置插入注釋。 這是呈現時的樣子:

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

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

ViewRef

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

Angular支持兩種類型的視圖:

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

創建嵌入的視圖

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

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

創建宿主視圖

宿主視圖是在組件動態實例化時創建的。 可以使用ComponentFactoryResolver動態創建一個組件:

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

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

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

ViewContainerRef

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

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

通常,標記應該創建ViewContainer的地方的好候選者是ng-container元素。 它被渲染為一個注釋,所以它不會在DOM中引入多余的html元素。 以下是在組件模板的特定位置創建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
}

我們之前已經看到,如何從模板和組件手動創建兩種類型的視圖。 一旦我們有了一個視圖,我們可以使用插入方法將其插入到DOM中。 所以,下面是從模板中創建一個嵌入式視圖并將其插入到由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);}
}

通過這個實現,生成的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來自動創建視圖:

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

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

ngTemplateOutlet and ngComponentOutlet

ngTemplateOutlet

這個將一個DOM元素標記為ViewContainer,并在其中插入一個由模板創建的嵌入視圖,而不需要在組件類中明確地做到這一點。 這意味著上面我們創建視圖并將其插入到#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,不同之處在于它創建一個宿主視圖(實例化一個組件),而不是嵌入視圖。 你可以像這樣使用它:

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

總結

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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/391486.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/391486.shtml
英文地址,請注明出處:http://en.pswp.cn/news/391486.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

numpy1

1、NumPy包含的內容 1、ndarrray&#xff0c;高效的多維數組&#xff0c;提供了基于數組的便捷算術操作以及靈活的廣播功能&#xff1b; 2、對所有數組對象進行快速的矩陣計算&#xff0c;而無需編寫循環&#xff1b; 3、提供對硬盤中的數據的讀寫工具&#xff0c;并對內存映射…

我如何預測10場英超聯賽的確切結果

Is there a way to predict the outcome of any soccer game with 100% accuracy? The honest and simplest answer is…. no. Regardless of what your fantasy football friends say, there is absolutely no way to be 100% certain, but there is a proven, mathematical …

多迪技術總監揭秘:PHP為什么是世界上最好的語言?

PHP這么一個腳本語言&#xff0c;雖然他是web開發中&#xff0c;使用者最多的語言&#xff0c;最快最簡單的語言&#xff0c;生態環境和社區積累最深厚的語言&#xff0c;作為最好的編程語言&#xff0c;多迪技術總監為你介紹&#xff1a;PHP為什么是世界上最好的語言&#xff…

aws數據庫同步區別_了解如何通過使用AWS AppSync構建具有實時數據同步的應用程序

aws數據庫同步區別AWS AppSync automatically updates the data in web and mobile applications in real time, and updates data for offline users as soon as they reconnect. AWS AppSync會自動實時更新Web和移動應用程序中的數據&#xff0c;并在離線用戶重新連接后立即為…

leetcode 153. 尋找旋轉排序數組中的最小值(二分查找)

已知一個長度為 n 的數組&#xff0c;預先按照升序排列&#xff0c;經由 1 到 n 次 旋轉 后&#xff0c;得到輸入數組。例如&#xff0c;原數組 nums [0,1,2,4,5,6,7] 在變化后可能得到&#xff1a; 若旋轉 4 次&#xff0c;則可以得到 [4,5,6,7,0,1,2] 若旋轉 4 次&#xff0…

test1

test1 轉載于:https://www.cnblogs.com/Forever77/p/11434403.html

打印風車旋轉效果

1 while True: 2 for i in["/","-","\\","|"]: 3 print "%s\r" %i, 轉載于:https://www.cnblogs.com/feifei-cyj/p/7469333.html

深度學習數據自動編碼器_如何學習數據科學編碼

深度學習數據自動編碼器意見 (Opinion) When I first wanted to learn programming, I coded along to a 4 hour long YouTube tutorial.剛開始學習編程時&#xff0c;我編寫了長達4個小時的YouTube教程。 “Great,” I thought after finishing the course. “I know how to …

Angular 5.0 學習2:Angular 5.0 開發環境的搭建和新建第一個ng5項目

1.安裝Node.js 在開始工作之前&#xff0c;我們必須設置好開發環境。如果你的機器上還沒有Node.js和npm&#xff0c;請先安裝它們。去Node.js的官網&#xff0c;https://nodejs.org/en/&#xff0c;點擊下載按鈕&#xff0c;下載最新版本&#xff0c;直接下一步下一步安裝即可&…

leetcode 154. 尋找旋轉排序數組中的最小值 II(二分查找)

已知一個長度為 n 的數組&#xff0c;預先按照升序排列&#xff0c;經由 1 到 n 次 旋轉 后&#xff0c;得到輸入數組。例如&#xff0c;原數組 nums [0,1,4,4,5,6,7] 在變化后可能得到&#xff1a; 若旋轉 4 次&#xff0c;則可以得到 [4,5,6,7,0,1,4] 若旋轉 7 次&#xff0…

robot:根據條件主動判定用例失敗或者通過

場景&#xff1a; 當用例中的斷言部分需要滿足特定條件時才會執行&#xff0c;如果不滿足條件時&#xff0c;可以主動判定該用例為passed狀態&#xff0c;忽略下面的斷言語句。 如上圖場景&#xff0c;當每月1號時&#xff0c;表中才會生成上月數據&#xff0c;生成后數據不會再…

golang go語言_在7小時內學習快速簡單的Go編程語言(Golang)

golang go語言The Go programming language (also called Golang) was developed by Google to improve programming productivity. It has seen explosive growth in usage in recent years. In this free course from Micheal Van Sickle, you will learn how to use Go step…

使用MUI框架,模擬手機端的下拉刷新,上拉加載操作。

套用mui官方文檔的一句話&#xff1a;“開發者只需關心業務邏輯&#xff0c;實現加載更多數據即可”。真的是不錯的框架。 想更多的了解這個框架&#xff1a;http://dev.dcloud.net.cn/mui/ 那么如何實現下拉刷新&#xff0c;上拉加載的功能呢&#xff1f; 首先需要一個容器&am…

圖深度學習-第1部分

有關深層學習的FAU講義 (FAU LECTURE NOTES ON DEEP LEARNING) These are the lecture notes for FAU’s YouTube Lecture “Deep Learning”. This is a full transcript of the lecture video & matching slides. We hope, you enjoy this as much as the videos. Of cou…

Git上傳項目到github

2019獨角獸企業重金招聘Python工程師標準>>> Git入門 個人理解git就是一個上傳工具&#xff0c;同時兼具和svn一樣的版本控制功能&#xff08;此解釋純屬本人個人觀點&#xff09; Github是什么 github就是一個分布式版本管理系統&#xff08;反正我就是這么認為的…

ionic4 打包ios_學習Ionic 4并開始創建iOS / Android應用

ionic4 打包iosLearn how to use Ionic 4 in this full course for beginners from Awais Mirza. Ionic Framework is the free, open source mobile UI toolkit for developing high-quality cross-platform apps for native iOS, Android, and the web—all from a single Ja…

robot:當用例失敗時執行關鍵字(發送短信)

使用場景&#xff1a; 當用例失敗時需要通知對應人員&#xff0c;則需要在Teardown中&#xff0c;使用關鍵字Run Keyword If Test Failed Send Message關鍵字為自定義關鍵字&#xff0c;${content}為短信內容&#xff0c;${msg_receiver}為短信接收者列表。 當然執行成功時需要…

leetcode 263. 丑數

給你一個整數 n &#xff0c;請你判斷 n 是否為 丑數 。如果是&#xff0c;返回 true &#xff1b;否則&#xff0c;返回 false 。 丑數 就是只包含質因數 2、3 和/或 5 的正整數。 示例 1&#xff1a; 輸入&#xff1a;n 6 輸出&#xff1a;true 解釋&#xff1a;6 2 3 …

NTP同步

RedHat Linux NTP實施步驟1、 查看本系統與NTP服務器的時間偏差 ntpdate -d 192.168.142.114 [rootzabbix-proxy ~]# ntpdate -d 192.168.142.114 24 Aug 17:26:45 ntpdate[3355]: ntpdate 4.2.6p51.2349-o Fri Apr 13 12:52:28 UTC 2018 (1) Looking for host 192.168.142.…

項目經濟規模的估算方法_估算英國退歐的經濟影響

項目經濟規模的估算方法On June 23 2016, the United Kingdom narrowly voted in a country-wide referendum to leave the European Union (EU). Economists at the time warned of economic losses; the Bank of England produced estimates that that GDP could be as much …