前言

連續發了 20 幾天的文,能講的也都講了,邁向神乎其技之路只剩下掌握小地方了吧!
之前介紹過 <ng-content>ContentChild,還有個很類似的是 @ViewChild裝飾器,接著就來看看這是甚麼吧!

這篇建議搭配前一篇一起看。

@ViewChild

直接來看範例,這個範例大致跟 @ContentChild範例很像,但做了一點修改,晚點我們會做比較。

app.ts

import {Component}       from 'angular2/core';
import {ParentComponent} from './parent';
import {ChildComponent}  from './child';

@Component({
selector: 'my-app',
template: &lt;h2&gt;App Component&lt;/h2&gt; &lt;my-parent&gt;&lt;/my-parent&gt; ,
directives:[ParentComponent,ChildComponent]
})
export class AppComponent {
}

注意到 <my-parent></my-parent> 裡面不用包 <my-child> 了。

child.ts

import {Component} from 'angular2/core';

@Component({
selector: 'my-child',
template: &lt;div&gt;Child Component&lt;/div&gt;
})
export class ChildComponent {
name:string = 'childName';
}

child 保持不變

parent.ts

import {Component,ViewChild,AfterViewInit} from 'angular2/core';
import {ChildComponent}         from './child';

@Component({
selector: 'my-parent',
template: &lt;div&gt;Parent Component&lt;/div&gt; &lt;my-child&gt;&lt;/my-child&gt; ,
directives:[ChildComponent]
})
export class ParentComponent implements AfterViewInit{
@ViewChild(ChildComponent)
child:ChildComponent;

ngAfterViewInit() {
    console.log(this.child)
}

}

改成用 @ViewChild,一樣可以取得 child 的組件內容,不過要在 AfterViewInit 之後才會生效。

如果改成這樣

template: `
       <div>Parent Component</div>
       <my-child></my-child>
       <p>{{child.name}}</p>
    `

則會

因為你在他生效前就呼叫了!


Plunker

可以看到 child 在 parent 中被呼叫了

所以 @ViewChild 跟直接引入組件使用差在哪?

差在如果我們在 parent 的模板沒有使用到 <my-child> 的話,@ViewChild 就會無法調用 child 的組件內容。而如果直接引用 child 組件的話,不使用標籤也沒關係。

區分 @ContentChild 和 @ViewChild

  • @ContentChild 是組件中 selector 標籤閉合之間的子組件,意思就是在 AppComponent<my-parent> 裡面必須要包含 <my-child>,換言之決定權在「使用 <my-parent> 的組件」手上,也就是有 @ContentChild 的上一層。
  • @ViewChild 是組件模板當中的子組件,決定權在當前組件。

兩者都有複數形式,@ContentChildren@ViewChildren

什麼時候獲取到子組件的值?

  • @ContentChild 在父組件生命週期函數 ngAfterContentInit 之後可以獲取到
  • @ViewChild 在父組件生命週期函 ngAfterViewInit 之後可以獲取到