Angular2官方文檔對組件交互這塊有詳細的介紹-->文檔--組件之間的交互。按文檔介紹,組件間交互的方式一共有4種,包括:
我在這里只總結、詳細介紹3種我在項目中使用過的方法,看完本文大概能做到如下的效果:

創建項目,項目結構如下:

通過@Input、@Output裝飾器進行父、子組件間的通信
@Input:該屬性綁定用于父組件向子組件傳遞數據。子組件可以通過以下兩種方法截取屬性的變更:
@Output:該數據綁定用于子組件向父組件傳遞數據和事件。
<!--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、)點擊按鈕觸發發射事件,將數據傳送給父組件。)

@Input:父組件輸入的同時,子組件能同步獲取數據進行顯示。核心代碼如下:
//父組件parentPrint: any; //ts中,聲明一個變量[(ngModel)]="parentPrint" //html中,綁定變量,獲取用戶輸入//html中,將數據傳給子組件<app-child [fromParent]="parentPrint"></app-child> //子組件@Input() fromParent; //ts中,用于直接接收從父組件獲取的數據[(ngModel)]="fromParent" //html中,用于顯示數據
通過setter截聽輸入屬性值的變化,在子組件中聲明一個私有變量來獲取父組件傳遞過來的數據,從而屏蔽上層獲取下層信息。(簡單一點就是不讓父組件知道子組件用什么東西去接收傳過來的數據)通過這種方法也可以獲得同樣的效果。
//子組件 private _fromParent: any; //私有變量,通過setter獲取父組件的數據@Input() //通過setter獲取父組件的數據 set fromParent(fromParent: any) { this._fromParent = fromParent; } get fromParent(): any { return this._fromParent; }@Output:父組件接收子組件的數據時,子組件暴露一個EventEmitter屬性,當事件發生時,子組件利用該屬性emits(向上彈射)事件。父組件綁定到這個事件屬性,并在事件發生時作出回應。核心代碼如下:
//子組件@Output() fromChild = new EventEmitter<any>(); //暴露一個輸出屬性<button class="btn btn-primary" (click)="clickChild()">Output方式</button> //觸發發射函數,將數據發送給父組件 clickChild() { console.log('click child' , this.contentFromChild); this.fromChild.emit(this.contentFromChild); }//父組件[(ngModel)]="contentFromChild" //綁定輸出子組件的數據//使用子組件,綁定事件屬性<app-child [fromParent]="parentPrint" (fromChild)="fromChild($event)"></app-child>//事件處理函數 fromChild(event) { console.log(event); this.contentFromChild = event; }父組件通過調用@ViewChild()來獲取子組件的數據
如果父組件的類需要讀取子組件的屬性和值或調用子組件的方法時,就可以把子組件作為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導入引用private childComponent: ChildComponent; // 將子組件注入到私有屬性//獲取子組件數據并顯示clickView() { //直接獲取子組件的屬性 this.viewOutput = this.childComponent.contentFromChild; }//html[(ngModel)]="viewOutput" <button class="btn btn-primary" (click)="clickView()">ViewChild方式</button>
父組件和子組件通過服務來通訊
父組件和它的子組件共享同一個服務,利用該服務在家庭內部實現雙向通訊。
<!--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">父組件服務輸入:</label> <input type="text" class="form-control" id="serviceoutput" placeholder="服務輸入" [(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">子組件服務輸入:</label> <input type="text" class="form-control" id="serviceoutput" placeholder="服務輸入" [(ngModel)]="serviceInput" > </div> <button class="btn btn-primary" (click)="clickService()">Service方式</button> </div></div>
//服務//meditor.service.tsimport {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;}效果如下:

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

最后附上demo源碼:父子組件交互demo
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。
新聞熱點
疑難解答