iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 26
0
Modern Web

Angular 元件庫 NG-ZORRO 基礎入門系列 第 26

[Angular 元件庫 NG-ZORRO 基礎入門] Day 26 - 原始碼初窺: Select - Part 2

前言回顧

目前我們已經瞭解了 nz-select 元件的基本設計結構,我們昨天已經知道了 nz-select 被拆分為:nz-select-top-control / nz-option-container / nz-option 等部分,我們繼續來了解一下其實現過程。

元件模組

NzSelectTopControlComponent

我們先看一下 nz-select-top-control.component.ts,這個元件承擔了顯示已選專案的功能,我們檢視其程式碼發現 OnInit 中監聽了一些事件:

ngOnInit(): void {
  // 監聽彈出層開啟事件,自動 focus
  this.nzSelectService.open$.pipe(takeUntil(this.destroy$)).subscribe(open => {
	if (this.inputElement && open) {
	  setTimeout(() => this.inputElement.nativeElement.focus());
	}
  });
// 監聽清除事件,針對 search 搜尋模式
this.nzSelectService.clearInput$.pipe(takeUntil(this.destroy$)).subscribe(() => {
  this.setInputValue('');
});
// 點選選項後手動觸發變化檢測,更新頁面
this.nzSelectService.check$.pipe(takeUntil(this.destroy$)).subscribe(() => {
  this.cdr.markForCheck();
});
}

已選專案的展示直接使用了 nzSelectService.listOfCachedSelectedOption 的相關值(單選多選表現形式不同,更多內容檢視原始碼):

<!--selected label-->
<div *ngIf="nzSelectService.listOfCachedSelectedOption.length && nzSelectService.listOfSelectedValue.length"
	 class="ant-select-selection-selected-value"
	 [attr.title]="nzSelectService.listOfCachedSelectedOption[0]?.nzLabel"
	 [ngStyle]="selectedValueStyle">
  <ng-container *nzStringTemplateOutlet="nzCustomTemplate; context: { $implicit: nzSelectService.listOfCachedSelectedOption[0] }">
	<ng-container>{{ nzSelectService.listOfCachedSelectedOption[0]?.nzLabel }}</ng-container>
  </ng-container>
</div>

NzSelectService

我們在之前介紹過,因為元件拆分後,各個元件間的資料互動如果全部使用 @Input@Output 來管理,就稍顯複雜,使用 Service 則是更好的方案,結合 Rxjs 的 Subject 能夠在任意地方進行訂閱監聽,可以很好地做到資料同步。

大家可以檢視一下 nz-select.service.ts 發現,在 NzSelectService 中,很多事件都是通過 Rxjs 的 Subject 和 BehaviorSubject 實現,在不同元件中通過 subscribe 方法訂閱。
比如:

private listOfSelectedValueWithEmit$ = new BehaviorSubject<{ value: any[]; emit: boolean }>({
  value: [],
  emit: false
});
listOfSelectedValue$ = this.listOfSelectedValueWithEmit$.pipe(map(data => data.value));
// 在 nz-option-li.component.ts 中訂閱(簡略程式碼,詳細可前往Github檢視)
this.nzSelectService.listOfSelectedValue$.pipe(takeUntil(this.destroy$)).subscribe(list => {
  this.selected = isNotNil(list.find(v => this.nzSelectService.compareWith(v, this.nzOption.nzValue)));
  this.cdr.markForCheck();
});

這樣在合適的元件中進行監聽,可以做出相應的操作來改變樣式或 emit 事件。

Subject 和 BehaviorSubject

在使用過程中,BehaviorSubjectSubject 有什麼不同呢?我們通過一個例子來簡單介紹一下:

const subject = new Subject();
subject.next('subject data');
subject.subscribe(x => console.log(x)); // no data

const behaviorSubject = new BehaviorSubject();
behaviorSubject.next('behavior subject');
behaviorSubject.subscribe(x => console.log(x)); // 'behavior subject'

看出來了嗎?BehaviorSubject 可以立即發出最新的值,這對於某些元件訂閱事件是必要的,有時候必須立刻給出最新值從而保證元件資料的時效性,而不是等待下一次使用者操作去觸發。

總結 & 預告

其餘部分都是大同小異,我們不再詳細展開,本質上 nz-select 元件的核心就是元件拆分和資料同步,拆分元件的目的是便於維護和管理,但是這也會引出資料互動同步的問題,它是通過 Service 來進行資料管理, Rxjs 的 Subject 來傳遞/訂閱,保證了各部分元件的資料流穩定。

相關資料


上一篇
[Angular 元件庫 NG-ZORRO 基礎入門] Day 25 - 原始碼初窺: Select
下一篇
[Angular 元件庫 NG-ZORRO 基礎入門] Day 27 - 原始碼初窺: Message
系列文
Angular 元件庫 NG-ZORRO 基礎入門30

尚未有邦友留言

立即登入留言