Angular2 父子組件通信方式的示例
Angular2官方文檔對組件交互這塊有詳細(xì)的介紹-->文檔--組件之間的交互。按文檔介紹,組件間交互的方式一共有4種,包括:
- 通過輸入型綁定把數(shù)據(jù)從父組件傳到子組件(@Input decoration);子組件暴露一個EventEmitter屬性(@Output decoration),當(dāng)事件發(fā)生時,利用該屬性emits向父組件發(fā)射事件。
- 父組件與子組件通過本地變量互動。(# var)
- 父組件調(diào)用@ViewChild。
- 父組件和子組件通過服務(wù)來通訊。
我在這里只總結(jié)、詳細(xì)介紹3種我在項(xiàng)目中使用過的方法,看完本文大概能做到如下的效果:

創(chuàng)建項(xiàng)目,項(xiàng)目結(jié)構(gòu)如下:

通過@Input、@Output裝飾器進(jìn)行父、子組件間的通信
@Input:該屬性綁定用于父組件向子組件傳遞數(shù)據(jù)。子組件可以通過以下兩種方法截取屬性的變更:
- 使用一個輸入屬性的setter,以攔截父組件中值得變化。
- 通過ngOnchanges()來截聽輸入屬性值的變化。
@Output:該數(shù)據(jù)綁定用于子組件向父組件傳遞數(shù)據(jù)和事件。
<!--parent.component.html-->
<div style="width: 1000px;margin: auto">
<div class="card" style="width: 500px;float: left">
<div class="card-header">
父組件
</div>
<div class="card-body">
<h5 class="card-title">父組件</h5>
<div class="form-group">
<label for="input">父組件輸入:</label>
<input type="text"
class="form-control"
id="input"
placeholder="Input something"
[(ngModel)]="parentPrint"
>
<label for="output">父組件輸出:</label>
<input type="text"
class="form-control"
id="output"
placeholder="Output something"
[(ngModel)]="contentFromChild"
>
</div>
</div>
</div>
<app-child
[fromParent]="parentPrint"
(fromChild)="fromChild($event)"
></app-child>
</div>
<!--child.component.html-->
<div class="card" style="width: 500px;">
<div class="card-header">
子組件
</div>
<div class="card-body">
<h5 class="card-title">子組件</h5>
<div class="form-group">
<label for="input">子組件輸入:</label>
<input type="text"
class="form-control"
id="input"
placeholder="Input something"
[(ngModel)]="contentFromChild"
>
<label for="output">子組件輸出:</label>
<input type="text"
class="form-control"
id="output"
placeholder="Output something"
[(ngModel)]="fromParent"
>
</div>
<button class="btn btn-primary" (click)="clickChild()">Output方式</button>
</div>
</div>
效果如下:(1、父組件輸入,子組件可同步輸出;2、子組件輸入需要(3、)點(diǎn)擊按鈕觸發(fā)發(fā)射事件,將數(shù)據(jù)傳送給父組件。)

@Input:父組件輸入的同時,子組件能同步獲取數(shù)據(jù)進(jìn)行顯示。核心代碼如下:
//父組件 parentPrint: any; //ts中,聲明一個變量 [(ngModel)]="parentPrint" //html中,綁定變量,獲取用戶輸入 //html中,將數(shù)據(jù)傳給子組件 <app-child [fromParent]="parentPrint"></app-child> //子組件 @Input() fromParent; //ts中,用于直接接收從父組件獲取的數(shù)據(jù) [(ngModel)]="fromParent" //html中,用于顯示數(shù)據(jù)
通過setter截聽輸入屬性值的變化,在子組件中聲明一個私有變量來獲取父組件傳遞過來的數(shù)據(jù),從而屏蔽上層獲取下層信息。(簡單一點(diǎn)就是不讓父組件知道子組件用什么東西去接收傳過來的數(shù)據(jù))通過這種方法也可以獲得同樣的效果。
//子組件
private _fromParent: any; //私有變量,通過setter獲取父組件的數(shù)據(jù)
@Input() //通過setter獲取父組件的數(shù)據(jù)
set fromParent(fromParent: any) {
this._fromParent = fromParent;
}
get fromParent(): any {
return this._fromParent;
}
@Output:父組件接收子組件的數(shù)據(jù)時,子組件暴露一個EventEmitter屬性,當(dāng)事件發(fā)生時,子組件利用該屬性emits(向上彈射)事件。父組件綁定到這個事件屬性,并在事件發(fā)生時作出回應(yīng)。核心代碼如下:
//子組件
@Output() fromChild = new EventEmitter<any>(); //暴露一個輸出屬性
<button class="btn btn-primary" (click)="clickChild()">Output方式</button>
//觸發(fā)發(fā)射函數(shù),將數(shù)據(jù)發(fā)送給父組件
clickChild() {
console.log('click child' , this.contentFromChild);
this.fromChild.emit(this.contentFromChild);
}
//父組件
[(ngModel)]="contentFromChild" //綁定輸出子組件的數(shù)據(jù)
//使用子組件,綁定事件屬性
<app-child
[fromParent]="parentPrint"
(fromChild)="fromChild($event)"
></app-child>
//事件處理函數(shù)
fromChild(event) {
console.log(event);
this.contentFromChild = event;
}
父組件通過調(diào)用@ViewChild()來獲取子組件的數(shù)據(jù)
如果父組件的類需要讀取子組件的屬性和值或調(diào)用子組件的方法時,就可以把子組件作為ViewChild,注入到父組件里面。ViewChild顧名思義就是可以看見子組件里面的屬性和方法。
<!--parent.component.html-->
<div style="width: 1000px;margin: auto">
<div class="card" style="width: 500px;float: left">
<div class="card-header">
父組件
</div>
<div class="card-body">
<h5 class="card-title">父組件</h5>
<div class="form-group">
<label for="viewoutput">ViewChild父組件輸出:</label>
<input type="text"
class="form-control"
id="viewoutput"
placeholder="ViewChild父組件輸出"
[(ngModel)]="viewOutput"
>
</div>
<button class="btn btn-primary" (click)="clickView()">ViewChild方式</button>
</div>
</div>
<app-child></app-child>
</div>
<!--child.component.html-->
<div class="card" style="width: 500px;">
<div class="card-header">
子組件
</div>
<div class="card-body">
<h5 class="card-title">子組件</h5>
<div class="form-group">
<label for="input">子組件輸入:</label>
<input type="text"
class="form-control"
id="input"
placeholder="Input something"
[(ngModel)]="contentFromChild"
>
</div>
</div>
</div>
效果如下:

父組件核心代碼:
//ts
@ViewChild(ChildComponent) // 使用viewChild導(dǎo)入引用
private childComponent: ChildComponent; // 將子組件注入到私有屬性
//獲取子組件數(shù)據(jù)并顯示
clickView() {
//直接獲取子組件的屬性
this.viewOutput = this.childComponent.contentFromChild;
}
//html [(ngModel)]="viewOutput" <button class="btn btn-primary" (click)="clickView()">ViewChild方式</button>
父組件和子組件通過服務(wù)來通訊
父組件和它的子組件共享同一個服務(wù),利用該服務(wù)在家庭內(nèi)部實(shí)現(xiàn)雙向通訊。
<!--parent.component.html-->
<div style="width: 1000px;margin: auto">
<div class="card" style="width: 500px;float: left">
<div class="card-header">
父組件
</div>
<div class="card-body">
<h5 class="card-title">父組件</h5>
<div class="form-group">
<label for="serviceoutput">父組件服務(wù)輸入:</label>
<input type="text"
class="form-control"
id="serviceoutput"
placeholder="服務(wù)輸入"
[(ngModel)]="serviceInput"
>
</div>
<button class="btn btn-primary" (click)="clickService()">Service方式</button>
</div>
</div>
<app-child></app-child>
</div>
<!--child.component.html-->
<div class="card" style="width: 500px;">
<div class="card-header">
子組件
</div>
<div class="card-body">
<h5 class="card-title">子組件</h5>
<div class="form-group">
<label for="serviceoutput">子組件服務(wù)輸入:</label>
<input type="text"
class="form-control"
id="serviceoutput"
placeholder="服務(wù)輸入"
[(ngModel)]="serviceInput"
>
</div>
<button class="btn btn-primary" (click)="clickService()">Service方式</button>
</div>
</div>
//服務(wù)
//meditor.service.ts
import {Injectable} from '@angular/core';
import {Subject} from 'rxjs/Subject';
import {Observable} from 'rxjs/Observable';
@Injectable()
export class MeditorService {
private subject = new Subject<MeditorMsg>();
constructor() {}
// 獲取訂閱者
public getObservable(): Observable<MeditorMsg> {
return this.subject.asObservable();
}
// 推送信息
public push(msg: MeditorMsg) {
this.subject.next(msg);
}
}
// 中間者信息
export interface MeditorMsg {
id: string;
body: any;
}
效果如下:

父子組件的核心代碼類似,在構(gòu)造函數(shù)中將該服務(wù)實(shí)例注入到自身,父子組件都有一個唯一的id。無論是父組件還是子組件調(diào)用push()方法推送數(shù)據(jù),雙方都能接收到數(shù)據(jù),這時候就要根據(jù)id來判斷是要父組件使用數(shù)據(jù)還是子組件使用數(shù)據(jù)。核心代碼如下:
subscription: Subscription = null; //初始化一個訂閱對象
//子組件構(gòu)造函數(shù),用于監(jiān)聽數(shù)據(jù)推送
constructor(
private meditor: MeditorService
) {
this.subscription = meditor.getObservable().subscribe(
msg => {
console.log(msg);
if (msg.id === 'parent') { //id為parent,獲取父組件數(shù)據(jù)
this.serviceInput = msg.body;
}
}
);
}
// 子組件將數(shù)據(jù)推送到中間著,給訂閱者
clickService() {
this.meditor.push({id: 'parent', body: this.serviceInput});
}
//父組件構(gòu)造函數(shù),用于監(jiān)聽數(shù)據(jù)推送
constructor(
private meditor: MeditorService
) {
this.subscription = meditor.getObservable().subscribe(
msg => {
console.log(msg);
if (msg.id === 'child') { //id為child,獲取子組件數(shù)據(jù)
this.serviceInput = msg.body;
}
}
);
}
// 父組件將數(shù)據(jù)推送到中間著,給訂閱者
clickService() {
this.meditor.push({id: 'parent', body: this.serviceInput});
}
我上面寫的還不是很完善,就是在生命周期結(jié)束前,也就是在onDestroy周期中,要取消訂閱。
以上,就是最近在使用的組件交互的總結(jié)。個人覺得通過服務(wù)來交互的可擴(kuò)展性更強(qiáng)。例如,我們項(xiàng)目中用到了一個動態(tài)顯示的側(cè)欄,不同時期點(diǎn)擊顯示側(cè)欄要顯示不同的東西。這個時候把側(cè)欄作為父組件,子組件作為消息的一部分傳遞給父組件,父組件根據(jù)子組件名動態(tài)生成模板,顯示在側(cè)欄上面。說了這么多廢話大概就是下圖的意思:

最后附上demo源碼:父子組件交互demo
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
AngularJS獲取json數(shù)據(jù)的方法詳解
這篇文章主要介紹了AngularJS獲取json數(shù)據(jù)的方法,結(jié)合實(shí)例形式詳細(xì)分析了AngularJS獲取json數(shù)據(jù)的詳細(xì)步驟、操作技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-05-05
AngularJS實(shí)現(xiàn)標(biāo)簽頁的兩種方式
這篇文章分別給大家介紹了AngularJS實(shí)現(xiàn)標(biāo)簽頁的兩種方式,一種是通過普通指令實(shí)現(xiàn)標(biāo)簽頁,另外一種是通過自定義指令實(shí)現(xiàn)的標(biāo)簽頁,有需要的朋友們可以來參考借鑒,下面來一起看看吧。2016-09-09
angularjs實(shí)現(xiàn)簡單的購物車功能
這篇文章主要為大家詳細(xì)介紹了angularjs實(shí)現(xiàn)簡單的購物車功能 ,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-09-09
angular 未登錄狀態(tài)攔截路由跳轉(zhuǎn)的方法
今天小編就為大家分享一篇angular 未登錄狀態(tài)攔截路由跳轉(zhuǎn)的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-10-10
通過angular CDK實(shí)現(xiàn)頁面元素拖放的步驟詳解
這篇文章主要給大家介紹了關(guān)于如何通過angular CDK實(shí)現(xiàn)頁面元素拖放的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者使用angular具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
angular2中router路由跳轉(zhuǎn)navigate的使用與刷新頁面問題詳解
這篇文章主要給大家介紹了angular2中router路由跳轉(zhuǎn)navigate的使用與刷新頁面問題的相關(guān)資料,文中介紹的非常詳細(xì),對大家具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。2017-05-05

