1.父組件通過屬性綁定的方式將數(shù)組從上到下的流入到子組件中,子組件需要通過@Input裝飾器來獲取。
例如:
父組件為
@Component({
template: `
<ul class="list">
<li *ngFor="let contact of contacts">
<app-list-item [contact]="contact"></app-list-item>
</li>
</ul>
`
})
export class ListComponent implement OnInit{
this.contacts = data;
}
子組件為:
@Component({
template:`
<div class="contact-info">
<label class="contact-name">{{contact.name}}</label>
<label class="contact-tel">{{contact.telNum}}</label>
</div>
`
})
export class ListItemComponent implements OnInit{
@Input() contact: any = {};
}
2.子組件通過事件傳遞的方式向父組件傳遞數(shù)據(jù),子組件需要實(shí)例化EventEmitter類,并使用裝飾器@Output修飾這個(gè)輸出屬性。父組件通過事件綁定的方式來訂閱來自子組件觸發(fā)的事件。
父組件:
@Component({
template: `
<contact-collect [contact]="detail" (onCollect)="collectTheContact($event)"></contact-collect>
`
})
export class CollectionComponent implements OnInit{
detail: any = {};
collectTheContact(){
this.detail.collection == 0 ? this.detail.collection = 1 : this.detail.collection = 0;
}
}
父組件通過綁定自定義事件onCollect訂閱來自子組件觸發(fā)的事件。
子組件
@Component({
template: `<i (click)=collectionTheContact()>收藏</i>`
})
export class ContactCollectComponent{
@Input() contact: any = {};
@Output() onCollect = new EventEmitter<bollean>();
collectTheContact(){
this.onCollect.emit();
}
}
通過@Output將數(shù)據(jù)流向父組件。
3.父組件通過局部變量獲取子組件的引用、父組件使用@ViewChild獲取子組件的引用
(1)在父組件的模板中為子組件創(chuàng)建一個(gè)局部變量,就可以在父組件的模板中訪問子組件的所有屬性和方法。這個(gè)局部變量有局限性,因?yàn)槟0遄兞恐荒茉谀0逯惺褂?,父組件的類不能使用這個(gè)局部變量訪問子組件的屬性和方法。
例如
父組件:
@Component({
template:`
<contact-collect (click)="collect.collectTheContact()" #collect></contact-collect>
`
})
export class CollectionComponent{}
在父組件中為子組件創(chuàng)建了一個(gè)局部變量#collect,父組件就可以使用#collect調(diào)用子組件的方法collectTheContact()
子組件
@Component({
template:<i>收藏</i>
})
export class ContactCollectComponent{
detail: any = {};
collectTheContact(){
this.detail.collection == 0 ? this.detail.collection = 1 : this.detail.collection = 0;
}
}
(2)使用@ViewChid屬性裝飾器獲取子組件的引用,該方法獲取的引用可以在父組件類中使用。
@ViewChild()提供了一個(gè)參數(shù)來選擇將要引用的組件元素。這個(gè)參數(shù)可以是一個(gè)類的實(shí)例,也可以是字符串。
I.參數(shù)為類實(shí)例,表示父組件將綁定一個(gè)指令或者子組件實(shí)例
II.參數(shù)為字符串類型,相當(dāng)于在父組件中綁定一個(gè)模板局部變量,獲取到子組件的一個(gè)實(shí)例對(duì)象的引用。
參數(shù)為字符串
@ViewChild("dateRange")
private dateRange: OpsDateRangeComponent;
<ops-date-range #dateRange style="line-height: 29px"
(changeDateEvent)="dateListener($event)"></ops-date-range>
參數(shù)為類實(shí)例
@Component({
template:`
<contact-collect (click)="collectTheContact()"></contact-collect>
`
})
export class CollectionComponent{
@ViewChild(ContactCollectComponent) contactCollect: ContactCollectComponent;
ngAfterViewInit(){}
collectTheContact(){
this.contactCollect.collectTheContact();
}
}
組件內(nèi)容嵌入
<ng-content>標(biāo)簽用來渲染組件嵌入內(nèi)容。
例如:
@Component({
selector: 'example-content'
template: `
<div>
<h4>ng-content實(shí)例</h4>
<div style="background-color: gray">
<ng-content select="header"></ng-content>
</div>
</div>
`
})
class NgContentExampleComponent{}
<ng-content>中有一個(gè)select="header",用于匹配內(nèi)容。并填充到ng-content中。
使用
@Component({
selector:'app'
template:`
<example-content>
<header>Header content</header>
</exampe-content>
`
})
export class NgContentAppComponent{}
最后渲染成的是
<app>
<example-content>
<div>
<h4>ng-content</h4>
<div style="background-color: gray">
<header>Header content</header>
</div>
</div>
</example-content>
</app>
從圖中可以看出<header>Header content</header>被填充到了ng-content,select屬性是一個(gè)選擇器,類似于css的選擇器,可以有標(biāo)簽選擇器、類選擇器、屬性選擇器。
4.通過setter監(jiān)聽輸入屬性值的變化
使用一個(gè)輸入屬性的setter,來攔截父組件中值的變化,并采取行動(dòng)。
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-name-child',
template: '<h3>"{{name}}"</h3>'
})
export class NameChildComponent {
private _name = '';
@Input()
set name(name: string) {
this._name = (name && name.trim()) || '<no name set>';
}
get name(): string { return this._name; }
}
在組件Namechildcomponent的輸入屬性name上設(shè)置了setter,會(huì)將父組件傳回來的name去掉空格,或者將空值替換成默認(rèn)的字符串。
5.通過ngOnChanges()來監(jiān)聽輸入屬性值的變化
使用OnChanges聲明周期鉤子接口的ngOnChanges()方法來監(jiān)測輸入屬性值的變化并做出回應(yīng)。(相比于setter方式,該方式可以艦艇多個(gè)輸入屬性)
import { Component, Input, OnChanges, SimpleChange } from '@angular/core';
@Component({
selector: 'app-version-child',
template: `
<h3>Version {{major}}.{{minor}}</h3>
<h4>Change log:</h4>
<ul>
<li *ngFor="let change of changeLog">{{change}}</li>
</ul>
`
})
export class VersionChildComponent implements OnChanges {
@Input() major: number;
@Input() minor: number;
changeLog: string[] = [];
ngOnChanges(changes: {[propKey: string]: SimpleChange}) {
let log: string[] = [];
for (let propName in changes) {
let changedProp = changes[propName];
let to = JSON.stringify(changedProp.currentValue);
if (changedProp.isFirstChange()) {
log.push(`Initial value of ${propName} set to ${to}`);
} else {
let from = JSON.stringify(changedProp.previousValue);
log.push(`${propName} changed from ${from} to ${to}`);
}
}
this.changeLog.push(log.join(', '));
}
}
這個(gè)VersionChildComponent 組件會(huì)監(jiān)測major和minor屬性的變化,并把這些變化寫成日志報(bào)告出來。
VersionChildComponent 提供minor和major值,把修改它們值的方法綁定到按鈕上。
import { Component } from '@angular/core';
@Component({
selector: 'app-version-parent',
template: `
<h2>Source code version</h2>
<button (click)="newMinor()">New minor version</button>
<button (click)="newMajor()">New major version</button>
<app-version-child [major]="major" [minor]="minor"></app-version-child>
`
})
export class VersionParentComponent {
major = 1;
minor = 23;
newMinor() {
this.minor++;
}
newMajor() {
this.major++;
this.minor = 0;
}
}
父組件和子組件通過服務(wù)來進(jìn)行通訊
父組件和子組件共享同一個(gè)服務(wù),利用該服務(wù)在組件家族中實(shí)現(xiàn)雙向通訊。
例如:
服務(wù):
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
@Injectable()
export class MissionService {
// Observable string sources
private missionAnnouncedSource = new Subject<string>();
private missionConfirmedSource = new Subject<string>();
// Observable string streams
missionAnnounced$ = this.missionAnnouncedSource.asObservable();
missionConfirmed$ = this.missionConfirmedSource.asObservable();
// Service message commands
announceMission(mission: string) {
this.missionAnnouncedSource.next(mission);
}
confirmMission(astronaut: string) {
this.missionConfirmedSource.next(astronaut);
}
}
MissionControlComponent 提供服務(wù)的實(shí)例,并將其共享給它的子組件(通過 providers 元數(shù)據(jù)數(shù)組),子組件可以通過構(gòu)造函數(shù)將該實(shí)例注入到自身.
import { Component } from '@angular/core';
import { MissionService } from './mission.service';
@Component({
selector: 'app-mission-control',
template: `
<h2>Mission Control</h2>
<button (click)="announce()">Announce mission</button>
<app-astronaut *ngFor="let astronaut of astronauts"
[astronaut]="astronaut">
</app-astronaut>
<h3>History</h3>
<ul>
<li *ngFor="let event of history">{{event}}</li>
</ul>
`,
providers: [MissionService]
})
export class MissionControlComponent {
astronauts = ['Lovell', 'Swigert', 'Haise'];
history: string[] = [];
missions = ['Fly to the moon!',
'Fly to mars!',
'Fly to Vegas!'];
nextMission = 0;
constructor(private missionService: MissionService) {
missionService.missionConfirmed$.subscribe(
astronaut => {
this.history.push(`${astronaut} confirmed the mission`);
});
}
announce() {
let mission = this.missions[this.nextMission++];
this.missionService.announceMission(mission);
this.history.push(`Mission "${mission}" announced`);
if (this.nextMission >= this.missions.length) { this.nextMission = 0; }
}
}
AstronautComponent 也通過自己的構(gòu)造函數(shù)注入該服務(wù)。由于每個(gè) AstronautComponent 都是 MissionControlComponent 的子組件,所以它們獲取到的也是父組件的這個(gè)服務(wù)實(shí)例。
import { Component, Input, OnDestroy } from '@angular/core';
import { MissionService } from './mission.service';
import { Subscription } from 'rxjs';
@Component({
selector: 'app-astronaut',
template: `
<p>
{{astronaut}}: <strong>{{mission}}</strong>
<button
(click)="confirm()"
[disabled]="!announced || confirmed">
Confirm
</button>
</p>
`
})
export class AstronautComponent implements OnDestroy {
@Input() astronaut: string;
mission = '<no mission announced>';
confirmed = false;
announced = false;
subscription: Subscription;
constructor(private missionService: MissionService) {
this.subscription = missionService.missionAnnounced$.subscribe(
mission => {
this.mission = mission;
this.announced = true;
this.confirmed = false;
});
}
confirm() {
this.confirmed = true;
this.missionService.confirmMission(this.astronaut);
}
ngOnDestroy() {
// prevent memory leak when component destroyed
this.subscription.unsubscribe();
}
}