原文見我的博客
組件之間的通訊是在angular2的開發(fā)中不可避免的,但是目前官方文檔上介紹的很模糊,不夠詳細(xì),本文將結(jié)合自己的學(xué)習(xí)和實(shí)踐來把官網(wǎng)上父組件和子組件通過服務(wù)來通訊的實(shí)例程序進(jìn)行詳細(xì)的說明。
父組件和它的子組件共享同一個(gè)服務(wù),利用該服務(wù)在家庭內(nèi)部實(shí)現(xiàn)雙向通訊,子組件中的數(shù)據(jù)的更新可以通過服務(wù)通知到其他的子組件。但是該服務(wù)實(shí)例的作用域被限制在父組件和其子組件內(nèi)。這個(gè)組件子樹之外的組件將無法訪問該服務(wù)或者與它們通訊。這樣的一個(gè)可以實(shí)現(xiàn)父子組件之間的通訊的服務(wù)的寫法和普通的服務(wù)的寫法是不同的是需要在服務(wù)中增加用于通知其他組件數(shù)據(jù)有更改的代碼,這個(gè)是通過import { Subject } from ‘rxjs/Subject’來實(shí)現(xiàn)的。
Subject的介紹
什么是Subject?在RxJS中,Subject是一類特殊的Observable,它可以向多個(gè)Observer多路推送數(shù)值。普通的Observable并不具備多路推送的能力(每一個(gè)Observer都有自己獨(dú)立的執(zhí)行環(huán)境),而Subject可以共享一個(gè)執(zhí)行環(huán)境。
我們看看MissionService
import{ Injectable } from'@angular/core';
import{ Subject } from'rxjs/Subject';
@Injectable()
exportclassMissionService {
//聲明變量 訂閱Observer,下面這個(gè)是一個(gè)可以實(shí)現(xiàn)組件之間通訊必不可少的
privatemissionAnnouncedSource =newSubject();
privatemissionConfirmedSource =newSubject();
missionAnnounced$ =this.missionAnnouncedSource.asObservable();
missionConfirmed$ =this.missionConfirmedSource.asObservable();
//當(dāng)組件或者服務(wù)中的數(shù)據(jù)有更改的時(shí)候調(diào)用這個(gè)方法即可將更改的數(shù)據(jù)推送到其他組件。
announceMission(mission: string) {
this.missionAnnouncedSource.next(mission);
}
confirmMission(astronaut: string) {
this.missionConfirmedSource.next(astronaut);
}
}
調(diào)用Subject對象的next(theValue) 方法后,Subject會(huì)向所有已經(jīng)在其上注冊的Observer多路推送數(shù)據(jù)。
現(xiàn)在我們來看看父組件
MissionControlComponent提供服務(wù)的實(shí)例,并將其共享給它的子組件(通過providers元數(shù)據(jù)數(shù)組),子組件可以通過構(gòu)造函數(shù)將該實(shí)例注入到自身。
import{ Component } from'@angular/core';
import{ MissionService } from'./mission.service';
@Component({
selector:'mission-control',
template: `
Mission Control
Announce mission
[astronaut]="astronaut">
History
{{event}}
`,
providers: [MissionService]
})
exportclassMissionControlComponent {
astronauts = ['Lovell','Swigert','Haise'];
history: string[] = [];
missions = ['Fly to the moon!',
'Fly to mars!',
'Fly to Vegas!'];
nextMission =0;
constructor(privatemissionService: 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; }
}
}
這個(gè)例子中服務(wù)的提供者在父組件中提供的,在實(shí)際的代碼中可能會(huì)報(bào)錯(cuò),可以將服務(wù)的提供者放到app.module.ts中。父組件中我們需要關(guān)注一點(diǎn)[astronaut]=”astronaut”,這個(gè)是把子組件中的變量和父組件中的變量綁定起來。這樣astronaut的值在其中一個(gè)子組件中有更改的時(shí)候服務(wù)通知的時(shí)候就可以通知父組件和其他綁定了這個(gè)變量的子組件。
我們在看看子組件:
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/Subscription';
@Component({
selector:'my-astronaut',
template: `
{{astronaut}}: **{{mission}}**
(click)="confirm()"
[disabled]="!announced || confirmed">
Confirm
`
})
exportclassAstronautComponentimplementsOnDestroy {
@Input() astronaut: string;
mission ='';
confirmed =false;
announced =false;
subscription: Subscription;
constructor(privatemissionService: MissionService) {
//根據(jù)自己的需要看是否需要
this.subscription = missionService.missionAnnounced$.subscribe(
mission => {
this.mission = mission;
this.announced =true;
this.confirmed =false;
});
}
//這里調(diào)用很關(guān)鍵,必須要有
confirm() {
this.confirmed =true;
this.missionService.confirmMission(this.astronaut);
}
ngOnDestroy() {
// prevent memory leak when component destroyed
this.subscription.unsubscribe();
}
}
在這個(gè)子組件中confirm方法調(diào)用了服務(wù)中的confirmMission來通知父組件astronaut的值已經(jīng)更改。注意,通過subscription服務(wù)訂閱任務(wù),并在AstronautComponent被銷毀的時(shí)候退訂。這是一個(gè)用于防止內(nèi)存泄漏的保護(hù)措施。實(shí)際上,在這個(gè)應(yīng)用程序中并沒有這個(gè)風(fēng)險(xiǎn),因?yàn)锳stronautComponent的生命期和應(yīng)用程序的生命期一樣長。但在更復(fù)雜的應(yīng)用程序環(huán)境中就不一定了。
總結(jié):angular2父組件和子組件通過服務(wù)來通訊主要有3點(diǎn)
一、在服務(wù)中使用訂閱來想各個(gè)組件推動(dòng)數(shù)據(jù);
二、在父組件的模板中綁定屬性,父子組件中的構(gòu)造函數(shù)同時(shí)使用服務(wù)參數(shù);
三、在子組件中調(diào)用服務(wù)中的推送來推送數(shù)據(jù)更改,其他子組件可以通過ngOnChanges來檢查更改然后做出相應(yīng)的處理。