实现一个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多选下拉框。