angular6.x系列的學習筆記記錄,仍在不斷完善中,學習地址:css
(1)組件詳解之模板語法ide
(2)組件詳解之組件通信post
(3)內容投影, ViewChild和ContentChild學習
(4)指令ui
(5)路由this
一個事物的出現,必然存在它所能解決的問題,讓咱們先從問題出發吧:spa
你們應該都知道,在html規範裏面,它定義了很是多的標籤,在這些標籤裏面,相同標籤之間的嵌套,不一樣標籤之間的嵌套,是十分常見,而且可行.net
同時,在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原生標籤或者其餘的自定義組件標籤,從而使它們沒法產生任何效果
上述問題經過內容投影則可以解決,那麼如何使用內容投影呢?
只須要在組件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再也不贅述
(終)
文檔信息
感謝您的閱讀,若是您以爲閱讀本文對您有幫助,請點一下「推薦」按鈕。本文歡迎各位轉載,可是轉載文章以後必須在文章頁面中給出做者和原文鏈接。