angular6.x系列的學習筆記記錄,仍在不斷完善中,學習地址:
系列目錄
(1)組件詳解之模板語法
(2)組件詳解之組件通訊
(3)內容投影, ViewChild和ContentChild
(4)指令
(5)路由
內容投影
1為什么需要內容投影?
一個事物的出現,必然存在它所能解決的問題,讓我們先從問題出發吧:
大家應該都知道,在html規范里面,它定義了非常多的標簽,在這些標簽里面,相同標簽之間的嵌套,不同標簽之間的嵌套,是十分常見,並且可行
同時,在Angular里面,我們可以通過自定義標簽的方式引用組件,那么這里的標簽能否像原生的html標簽一樣,來嵌入html標簽,或者嵌套其他組件標簽呢?
於是就引入我們今天的主要問題,用一個詳細的例子來描述吧:
假設存在父組件Content,和它下面2個子組件PartA和PartB,自定義標簽分別為:<app-content>,<app-content-part-a>,<app-content-part-b>,目錄結構如下

如果想在父組件的視圖里面,完成下面的內容,是否可行呢?
content.component.html
1 <div> 2 <div>Content</div> 3 <div> 4 <app-content-part-a> 5 <h1>PartA--start</h1> 6 <app-content-part-b></app-content-part-b> 7 <span>PartA--end</span> 8 </app-content-part-a> 9 </div> 10 </div>
這樣是不行的,其結果只會顯示自定義的組件<app-content-part-a>自身的內容,因為自定義組件標簽會忽略嵌套其中的html原生標簽或者其他的自定義組件標簽,從而使它們無法產生任何效果
2如何使用內容投影?
上述問題通過內容投影則能夠解決,那么如何使用內容投影呢?
只需要在組件PartA的視圖里面做一些改動,內容如下
part-a.component.html
1 <div> 2 <div> 3 <ng-content select="h1"></ng-content> 4 </div> 5 <div> 6 <ng-content select="app-content-part-b"></ng-content> 7 </div> 8 <div> 9 <ng-content select="span"></ng-content> 10 </div> 11 </div>
經過這樣的修改,上述想要實現的效果就可以達到
那么內容投影是如何工作的呢?
首先通過angular里面的一個指令ng-content,實現占位,再通過select,達到選擇器的作用,這樣在組件生命周期過程,初始渲染投影內容的時候,就能夠將對應的內容投影到特定的位置,這就是內容投影工作的簡單描述
組件里面嵌套組件,之間的通訊問題可以參考組件間的通訊
ContentChild和ViewChild
首先做個簡單的介紹:
ContentChild:與內容子節點有關,操作投影進來的內容;
ViewChild:與視圖子節點有關,操作自身的視圖內容;
在上一部分,我們通過內容投影,讓自定義的組件標簽能夠嵌入html標簽或自定義組件標簽,那么它如何操作投影進來的內容呢?
還是以上述內容為例,從實際的問題出發:假設嵌入的自定義組件標簽<app-content-part-b>里面聲明了一個方法func(),那么如何在<app-content-part-a>里面去操作這個方法呢?
上面說過,ContentChild是操作投影進來的內容,那么在這里我們也可以通過它解決問題,在組件PartA內,通過ContentChild獲取投影進來的組件PartB,並對它進行操作(部分代碼在上一部分已經貼出,這一部分不予重復),代碼如下
part-b.component.ts
1 import { Component, OnInit,Output} from '@angular/core'; 2 3 @Component({ 4 selector: 'app-content-part-b', 5 templateUrl: './part-b.component.html', 6 styleUrls: ['./part-b.component.scss'] 7 }) 8 export class PartBComponent implements OnInit { 9 constructor() { } 10 11 ngOnInit() { 12 } 13 14 public func():void{ 15 console.log("PartB"); 16 } 17 }
part-a.component.ts
1 import { Component, OnInit, ContentChild } from '@angular/core'; 2 import { PartBComponent } from '../part-b/part-b.component'; 3 4 @Component({ 5 selector: 'app-content-part-a', 6 templateUrl: './part-a.component.html', 7 styleUrls: ['./part-a.component.scss'] 8 }) 9 export class PartAComponent implements OnInit { 10 11 @ContentChild(PartBComponent) PartB:PartBComponent 12 13 constructor() { } 14 15 ngOnInit() {} 16 17 ngAfterContentInit(): void { 18 this.PartB.func(); 19 } 20 }
這里需要注意一點:在組件的生命周期里面,有一個鈎子ngAfterContentInit()是與投影內容初始化有關,所以我們有關投影的內容操作盡量放在它初始化完成之后進行
如果理解了ContentChild的用法,那么ViewChild幾乎沒有理解難度,他們的差異不大,所不同的是:
1ViewChild是操作視圖本身存在的節點,而不是投影進來的內容
2ngAfterContentInit()對應的是ngAfterViewInit()(視圖節點初始化是在投影內容初始化之后)
其他沒有什么不同,這里我就不再贅述
ContentChild和ViewChild還存在復數的形式,即ContentChildren和ViewChildren,它們取到的是節點的一個集合,其他的沒有什么區別
寫法如下:
1 import { Component, OnInit, ContentChild,ContentChildren ,QueryList } from '@angular/core'; 2 import { PartBComponent } from '../part-b/part-b.component'; 3 4 @Component({ 5 selector: 'app-content-part-a', 6 templateUrl: './part-a.component.html', 7 styleUrls: ['./part-a.component.scss'] 8 }) 9 export class PartAComponent implements OnInit { 10 11 @ContentChildren(PartBComponent) 12 PartBs: QueryList<PartBComponent>; 13 14 constructor() { } 15 16 ngOnInit() {} 17 18 }
上述代碼中PartBs是組件PartB的一個集合,這就是復數的用法,ViewChildren不再贅述
(終)
文檔信息
- 發表作者: 半路獨行
- 發表出處: 博客園
- 原文地址: https://www.cnblogs.com/banluduxing/p/10394387.html
- 版權信息:
本作品采用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。
感謝您的閱讀,如果您覺得閱讀本文對您有幫助,請點一下“推薦”按鈕。本文歡迎各位轉載,但是轉載文章之后必須在文章頁面中給出作者和原文連接。
