組件指令間常常須要溝通 git
咱們知道的方式有 github
input編程
outputapi
servicethis
injectspa
viewchildcode
contentchildcomponent
templateReform
template variable對象
可是哪一種狀況下用哪一種呢 ?
思考 1, input -> input -> input 這種一層層傳進去是不是 ok 的 ?
<mat-calendar cdkTrapFocus [id]="datepicker.id" [ngClass]="datepicker.panelClass" [startAt]="datepicker.startAt" [startView]="datepicker.startView" [minDate]="datepicker._minDate" [maxDate]="datepicker._maxDate" [dateFilter]="datepicker._dateFilter" [headerComponent]="datepicker.calendarHeaderComponent" [selected]="datepicker._selected" [dateClass]="datepicker.dateClass" [@fadeInCalendar]="'enter'" (selectedChange)="datepicker.select($event)" (yearSelected)="datepicker._selectYear($event)" (monthSelected)="datepicker._selectMonth($event)" (_userSelection)="datepicker.close()"> </mat-calendar>
看看人家 material datepicker
datepicker 指令經過 overlay 建立 datepickerContent 組件, 而後 this._popupComponentRef.instance.datepicker = this; 把本身傳進去, 在把 datepicker input 一個個放入 mat-calendar input (上圖)
private _openAsPopup(): void { if (!this._calendarPortal) { this._calendarPortal = new ComponentPortal<MatDatepickerContent<D>>(MatDatepickerContent, this._viewContainerRef); } if (!this._popupRef) { this._createPopup(); } if (!this._popupRef.hasAttached()) { this._popupComponentRef = this._popupRef.attach(this._calendarPortal); this._popupComponentRef.instance.datepicker = this; this._setColor(); // Update the position once the calendar has rendered. this._ngZone.onStable.asObservable().pipe(take(1)).subscribe(() => { this._popupRef.updatePosition(); }); } }
因此你說 input -> input 又如何呢 ?
我我的以爲 wrap component 就一層一層傳咯, 無所謂的啦.
思考 2 : output vs input callback function
<abc (submit)="submit($event)" [submitFn]="submitFn" ></abc>
output 是廣播的概念, 廣播的缺點就是沒有的寫 callback,
假設我想封裝一個 submit loading, submit 由外部負責, 那麼我寫一個 output 我就沒法知道何時 loading 結束, 除非外部又 input 一個 submit 結束進來.
若是是 input + callback 就容易.
可是 input + callback 也有問題就是不能任意輸入變量
好比 (submit)="submit($event, index)" 能夠很簡單的傳入 ngFor 的 index, 而 submitFn 就不行了.
廣播後有一種方式能夠跟外部溝通就是經過 event
好比 event.preventDefault() 就是一個通信.
咱們能夠作一個 event.submitDone() 來通知內部, submit 結束了,讓 loading 關閉.
可是這種方式仍是有點詭異, 畢竟廣播的概念是能夠多我的監聽. 這個 submitDone 視乎指定了一個監聽者在使用..
最後我也不知道如何是好啦.
思考 3 : ng-content vs input ng-template
content 很直觀, 可是缺點也很恐怖, 就是隻能一層. 你 wrap 一個 component 基本上 content 就廢了.
怎麼說廢了呢, 由於 contentchild 會獲取不了
https://github.com/angular/angular/issues/20810
https://github.com/angular/angular/issues/8563
看看 material table
https://github.com/angular/material2/issues/6980
若是你 wrap 了 material table, 你須要經過 viewchild 找到 mat table 而後調用 api 來把 content 輸入進去. 是否是麻煩 ?
對比 ng-template 或者 dynamic component 就不一樣了. 經過 input 輸入, 就能夠傳到底層, 好比 material datepicker 的 header component.
此外它們還有很大的不一樣在於使用.
看看 material select , material option group , material option 的配搭.
若是用 template 實現就很不一樣了.
這個例子中 option 是外部負責 ngfor 建立而後傳入的, template 要實現的話. 你只能傳入 items + template 內部實現 ngfor 渲染 template.
思考 4: template variable
<form class="example-form"> <mat-form-field class="example-full-width"> <input type="text" placeholder="Pick one" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto"> <mat-autocomplete #auto="matAutocomplete"> <mat-option *ngFor="let option of options" [value]="option"> {{option}} </mat-option> </mat-autocomplete> </mat-form-field> </form>
注意 mat-autocomplete 和 input 是如何連上的嗎 ?
經過一個指令 [matAutocomplete] + template variable
若是你熟悉面向對象編程, 而後把 component 想象成 new ComponentClass 獲得的對象.
那麼你會發現模板之間就是 對象與對象的互相方法調用,修改屬性而已.
因此當你 new 了不少 component 後,你要他們一塊兒工做,你就須要讓它們互相依賴.
好比
let input = new Input();
let autoDir = new AutoDir();
let auto = new Auto();
autoDir.auto = auto;
autoDir.input = input;
autoDir.watchInputThenOpenAuto();
watchInputThenOpenAuto(){
this.input.change(() => { this.auto.open().filterBy(this.input.value); });
}