Angular CDK Virtual scroll 没有一次选择 matselect 中的所有列大型数据集
Angular CDK Virtual scroll not selecting all columns in matselect at once large dataset
我在 angular 中有一个 mat-select 像这样带有虚拟滚动。
<mat-select [formControl]="multiSelectControl" multiple [value]="selected" (openedChange)="openChange($event)">
<cdk-virtual-scroll-viewport itemSize="5" minBufferPx="200" maxBufferPx="400" [style.height.px]=5*48>
<button (click)="selectAll()">Select All</button>
<button (click)="clear()">Clear</button>
<mat-option *cdkVirtualFor="let topping of toppingList" [value]="topping" (onSelectionChange)="onSelectionChange($event)">{{topping}}</mat-option>
</cdk-virtual-scroll-viewport>
</mat-select>
.ts 文件:
@ViewChildren(MatOption)
options: QueryList<MatOption>;
constructor(private cd: ChangeDetectorRef) {}
ngAfterViewInit(): void {
this.options.changes.subscribe(() => {
let needUpdate = false;
this.options.forEach((option) => {
const selected = this.selected.includes(option.value);
if (selected && !option.selected) {
option.select();
needUpdate = true;
} else if (!selected && option.selected) {
option.deselect();
needUpdate = true;
}
});
if (needUpdate) {
this.cd.detectChanges();
}
});
}
onSelectionChange(change): void {
if (!change.isUserInput) {
return;
}
const value = change.source.value;
const idx = this.selected.indexOf(change.source.value);
if (idx > -1) {
this.selected.splice(idx, 1)
} else {
this.selected.push(value);
}
}
与 stackblitz link。
如果我单击 Select 全部并更快地滚动,所有元素都不会得到 selected,因为它们需要时间才能得到 selected。有什么办法可以提高性能吗
一个选项是在 ScrollDispatcher
:
上收听滚动的 Observable
ngAfterViewInit(): void {
this.sd.scrolled().pipe(
filter((scrollable) => this.cdkVirtualScrollViewPort === scrollable)
).subscribe(() => {
let needUpdate = false;
this.options.forEach((option) => {
const selected = this.selected.includes(option.value);
if (selected && !option.selected) {
option.select();
needUpdate = true;
} else if (!selected && option.selected) {
option.deselect();
needUpdate = true;
}
});
if (needUpdate) {
this.cd.detectChanges();
}
});
}
您可能会去抖事件,这样它就不会被触发太多。我已经用这个解决方案更新了 stackblitz
我在 angular 中有一个 mat-select 像这样带有虚拟滚动。
<mat-select [formControl]="multiSelectControl" multiple [value]="selected" (openedChange)="openChange($event)">
<cdk-virtual-scroll-viewport itemSize="5" minBufferPx="200" maxBufferPx="400" [style.height.px]=5*48>
<button (click)="selectAll()">Select All</button>
<button (click)="clear()">Clear</button>
<mat-option *cdkVirtualFor="let topping of toppingList" [value]="topping" (onSelectionChange)="onSelectionChange($event)">{{topping}}</mat-option>
</cdk-virtual-scroll-viewport>
</mat-select>
.ts 文件:
@ViewChildren(MatOption)
options: QueryList<MatOption>;
constructor(private cd: ChangeDetectorRef) {}
ngAfterViewInit(): void {
this.options.changes.subscribe(() => {
let needUpdate = false;
this.options.forEach((option) => {
const selected = this.selected.includes(option.value);
if (selected && !option.selected) {
option.select();
needUpdate = true;
} else if (!selected && option.selected) {
option.deselect();
needUpdate = true;
}
});
if (needUpdate) {
this.cd.detectChanges();
}
});
}
onSelectionChange(change): void {
if (!change.isUserInput) {
return;
}
const value = change.source.value;
const idx = this.selected.indexOf(change.source.value);
if (idx > -1) {
this.selected.splice(idx, 1)
} else {
this.selected.push(value);
}
}
与 stackblitz link。
如果我单击 Select 全部并更快地滚动,所有元素都不会得到 selected,因为它们需要时间才能得到 selected。有什么办法可以提高性能吗
一个选项是在 ScrollDispatcher
:
Observable
ngAfterViewInit(): void {
this.sd.scrolled().pipe(
filter((scrollable) => this.cdkVirtualScrollViewPort === scrollable)
).subscribe(() => {
let needUpdate = false;
this.options.forEach((option) => {
const selected = this.selected.includes(option.value);
if (selected && !option.selected) {
option.select();
needUpdate = true;
} else if (!selected && option.selected) {
option.deselect();
needUpdate = true;
}
});
if (needUpdate) {
this.cd.detectChanges();
}
});
}
您可能会去抖事件,这样它就不会被触发太多。我已经用这个解决方案更新了 stackblitz