實現一個angular多選下拉框組件,當有超過2000個選項時,滑動/挑選/全選均不卡。css
爲了方便,這裏不考慮擴展性,因此規定下拉框展開只顯示7行數據,行高27pxhtml
export class SelectItem {
public label: string;
public value: string;
public disabled?: boolean; // 某些選項禁用
public groupKey?: string; // 給選項分組用
public groupHead?: string; // 顯示選項組
public checked?: boolean; // 是否打勾
public tempChecked?: boolean; // 是否臨時打勾(用戶要求,自動保存選項的話不須要)
public originalCheckStatus?: boolean; // 放棄保存(用戶要求,自動保存選項的話不須要)
}複製代碼
this.actualList = this.list.slice(0, 8); // 多截兩個當緩衝複製代碼
.list-container {height: 162px;}複製代碼
<div class="list-container"> <div *ngFor="let item of actualList; trackBy: trackByValue" class="inner-option"> <label> <input type="checkbox" [(ngModel)]="item.checked"> <span>{{item.label}}</span> </label> </div> <div>複製代碼
<div class="list-container">
<div [style.height]="scrollHeight">
<div *ngFor="let item of actualList; trackBy: trackByValue" class="inner-option">
<label>
<input type="checkbox" [(ngModel)]="item.checked">
<span>{{item.label}}</span>
</label>
</div>
</div>
</div>複製代碼
this.scrollHeight = this.list.length * 27;複製代碼
.list-container {
height: 162px;
overflow: auto; // 固然你要讓這個外層溢出後加滾動
}複製代碼
這樣你就獲得了一個看起來能夠滾動的可是其實只有第一頁的下拉框。而後你要作的就是在用戶滾動以後動態的更新actualList,這裏咱們能夠用angular封裝好的scroll event:前端
<div class="list-container" (scroll)="onScroll($event)">
<div [style.height]="scrollHeight">
<div *ngFor="let item of actualList; trackBy: trackByValue" class="inner-option">
<label>
<input type="checkbox" [(ngModel)]="item.checked">
<span>{{item.label}}</span>
</label>
</div>
</div>
</div>複製代碼
public onScroll(e) {
const firstIndex = Math.floor(e.target.scrollTop / 27);
const secondIndex = firstIndex + 8;
this.actualList = this.list.slice(firstIndex, secondIndex);
}複製代碼
以上雖然你是更新了能夠顯示的實際list,可是尚未在面板上顯示出來,由於這個actualList被你劃上去了,因此接下來須要在滾動時動態的把這一塊往下/上移,這裏咱們用translateYnode
public onScroll(e) {
...
this.translateY = `translateY(${firstIndex * 27}px)`;
}複製代碼
<div>
...
<div *ngFor=....class="inner-option" [style.transform]="translateY">
...
</div>複製代碼
其實到這裏核心的整個虛擬滾動的列表就製做完成了,剩下的工做包括:react
下篇再說typescript
---------------------------------其餘-----------------------------bootstrap
背景:數組
目前市面上的不少下拉框(包括bootstrap的各類angular/react實現,kendoUI,antd)都尚未考慮大數據量的狀況。這樣的話一旦數據突破4000條(單選)/1000(多選),瀏覽器就會變卡,由於DOM tree已經繪製了全部這些nodes。瀏覽器
吐槽:bash
這種狀況不多見,但不是沒有,好比咱們的場景是容許用戶建立本身的條目,一旦共享以後這條項目就會出如今某個多選框裏讓其餘人自由組合使用,數據量就很容易變大。
發現:
Angular更新7的時候我注意到他們的material design庫新增長了一個新玩意:虛擬滾動。本質上就是隻繪製用戶看到的節點去極大地節省內存開銷。blog.angular.io/version-7-o…
過了不久後看見了阿健大叔在前端之巔發表的《如何用react+rxjs實現一個虛擬滾動組件》受啓發,就決定用這種思想重寫咱們正在用的angular多選下拉框。