Angular14中cdk-virtual-scroll-viewport内mat-list-option选中状态丢失求助
解决Angular 14中虚拟滚动选择列表选中状态丢失问题
问题原因
Angular 14版本中,Angular Material对mat-selection-list的内部实现进行了调整,原Angular 11中直接在mat-selection-list内嵌套cdk-virtual-scroll-viewport的结构,会导致虚拟滚动复用列表项时,mat-selection-list无法正确跟踪所有选项的选中状态,最终出现滚动后选中状态丢失的情况。
修复方案
核心调整点
- 添加
trackBy函数:虚拟滚动会销毁和重建可视区域外的列表项,通过trackBy函数让Angular识别列表项的唯一标识,避免复用错误的状态。 - 简化状态同步逻辑:直接针对
selectionChange事件返回的单个选项处理选中/取消操作,确保状态同步准确且无冗余。 - 保持
[selected]绑定与SelectionModel的强关联:让列表项每次重建时都从SelectionModel读取最新状态。
修改后的代码
HTML模板
<mat-selection-list (selectionChange)="onSelectionChange($event)"> <cdk-virtual-scroll-viewport [itemSize]="20" class="example-viewport"> <mat-list-option *cdkVirtualFor="let item of list; trackBy: trackByFn" [value]="item" [selected]="selection.isSelected(item)" > {{item}} </mat-list-option> </cdk-virtual-scroll-viewport> </mat-selection-list>
TypeScript代码
import { Component } from '@angular/core'; import { SelectionModel } from '@angular/cdk/collections'; import { MatSelectionListChange } from '@angular/material/list'; @Component({ selector: 'app-list-selection', templateUrl: './list-selection.component.html', styleUrls: ['./list-selection.component.css'] }) export class ListSelectionComponent { selection = new SelectionModel<number>(true); list = Array.from(Array(10000).keys()); trackByFn(index: number, item: number): number { return item; } onSelectionChange(event: MatSelectionListChange): void { const targetOption = event.option; targetOption.selected ? this.selection.select(targetOption.value) : this.selection.deselect(targetOption.value); } }
关键说明
trackByFn通过列表项的唯一值(此处为数字本身)作为标识,确保虚拟滚动重建列表项时能正确匹配SelectionModel中的状态。[selected]="selection.isSelected(item)"保证每次列表项重建时,都会从SelectionModel中读取正确的选中状态,不会因为组件复用而丢失状态。- 简化后的
onSelectionChange逻辑直接处理当前变化的选项,避免了不必要的遍历,提升性能的同时确保状态同步准确。
内容的提问来源于stack exchange,提问作者Timuçin Çiçek
相关产品推荐
相关产品推荐

