原文見我的博客
組件之間的通訊是在angular2的開發(fā)中不可避免的,但是目前官方文檔上介紹的很模糊把跨,不夠詳細故硅,本文將結(jié)合自己的學(xué)習(xí)和實踐來把官網(wǎng)上父組件和子組件通過服務(wù)來通訊的實例程序進行詳細的說明。
父組件和它的子組件共享同一個服務(wù),利用該服務(wù)在家庭內(nèi)部實現(xiàn)雙向通訊渠羞,子組件中的數(shù)據(jù)的更新可以通過服務(wù)通知到其他的子組件。但是該服務(wù)實例的作用域被限制在父組件和其子組件內(nèi)智哀。這個組件子樹之外的組件將無法訪問該服務(wù)或者與它們通訊次询。這樣的一個可以實現(xiàn)父子組件之間的通訊的服務(wù)的寫法和普通的服務(wù)的寫法是不同的是需要在服務(wù)中增加用于通知其他組件數(shù)據(jù)有更改的代碼,這個是通過import { Subject } from ‘rxjs/Subject’來實現(xiàn)的瓷叫。
Subject的介紹
什么是Subject屯吊?在RxJS中,Subject是一類特殊的Observable摹菠,它可以向多個Observer多路推送數(shù)值盒卸。普通的Observable并不具備多路推送的能力(每一個Observer都有自己獨立的執(zhí)行環(huán)境),而Subject可以共享一個執(zhí)行環(huán)境次氨。
我們看看MissionService
import{ Injectable } from'@angular/core';
import{ Subject } from'rxjs/Subject';
@Injectable()
exportclassMissionService {
//聲明變量 訂閱Observer蔽介,下面這個是一個可以實現(xiàn)組件之間通訊必不可少的
privatemissionAnnouncedSource =newSubject();
privatemissionConfirmedSource =newSubject();
missionAnnounced$ =this.missionAnnouncedSource.asObservable();
missionConfirmed$ =this.missionConfirmedSource.asObservable();
//當組件或者服務(wù)中的數(shù)據(jù)有更改的時候調(diào)用這個方法即可將更改的數(shù)據(jù)推送到其他組件。
announceMission(mission: string) {
this.missionAnnouncedSource.next(mission);
}
confirmMission(astronaut: string) {
this.missionConfirmedSource.next(astronaut);
}
}
調(diào)用Subject對象的next(theValue) 方法后煮寡,Subject會向所有已經(jīng)在其上注冊的Observer多路推送數(shù)據(jù)虹蓄。
現(xiàn)在我們來看看父組件
MissionControlComponent提供服務(wù)的實例,并將其共享給它的子組件(通過providers元數(shù)據(jù)數(shù)組)幸撕,子組件可以通過構(gòu)造函數(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; }
}
}
這個例子中服務(wù)的提供者在父組件中提供的,在實際的代碼中可能會報錯坐儿,可以將服務(wù)的提供者放到app.module.ts中律胀。父組件中我們需要關(guān)注一點[astronaut]=”astronaut”,這個是把子組件中的變量和父組件中的變量綁定起來貌矿。這樣astronaut的值在其中一個子組件中有更改的時候服務(wù)通知的時候就可以通知父組件和其他綁定了這個變量的子組件炭菌。
我們在看看子組件:
AstronautComponent也通過自己的構(gòu)造函數(shù)注入該服務(wù)。由于每個AstronautComponent都是MissionControlComponent的子組件逛漫,所以它們獲取到的也是父組件的這個服務(wù)實例黑低。
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();
}
}
在這個子組件中confirm方法調(diào)用了服務(wù)中的confirmMission來通知父組件astronaut的值已經(jīng)更改尽楔。注意投储,通過subscription服務(wù)訂閱任務(wù),并在AstronautComponent被銷毀的時候退訂阔馋。這是一個用于防止內(nèi)存泄漏的保護措施玛荞。實際上,在這個應(yīng)用程序中并沒有這個風(fēng)險呕寝,因為AstronautComponent的生命期和應(yīng)用程序的生命期一樣長勋眯。但在更復(fù)雜的應(yīng)用程序環(huán)境中就不一定了。
總結(jié):angular2父組件和子組件通過服務(wù)來通訊主要有3點
一、在服務(wù)中使用訂閱來想各個組件推動數(shù)據(jù)客蹋;
二塞蹭、在父組件的模板中綁定屬性,父子組件中的構(gòu)造函數(shù)同時使用服務(wù)參數(shù)讶坯;
三番电、在子組件中調(diào)用服務(wù)中的推送來推送數(shù)據(jù)更改,其他子組件可以通過ngOnChanges來檢查更改然后做出相應(yīng)的處理辆琅。