mat-select-trigger结合cdk-virtual-scroll-viewport不生效问题求助
修复方案
问题根因
- mat-select未绑定选中值,且虚拟滚动初始化时不在视口内的
mat-option不会渲染,mat-select无法匹配到对应选项导致初始值不显示 - 未配置
cdkVirtualFor的trackBy函数,窗口resize触发虚拟滚动重渲染时,已选中的option节点被销毁重建导致选中态丢失 - 虚拟滚动视口未固定高度/滚动触发时机过早,导致选中项滚动定位失效
具体修改步骤
1. 模板修改
- 给
mat-select添加[value]绑定,同步选中值 - 给
*cdkVirtualFor添加trackBy配置,复用DOM节点 - 建议将选中变更事件绑定到
mat-select而非每个mat-option,减少不必要的事件监听
修改后模板代码:
<mat-select [value]="selected" (openedChange)="openChange($event)" (selectionChange)="onSelectionChange($event)" > <mat-select-trigger> <img src="assets/{{selected[1]}}.svg" alt=""/> + {{selected[0]}} </mat-select-trigger> <cdk-virtual-scroll-viewport itemSize="48" class="viewport"> <mat-option *cdkVirtualFor="let i of items; templateCacheSize: 20; trackBy: trackByItem" [value]="i" > <img src="assets/{{ i[1] }}.svg" alt=""/> + {{i[0]}} </mat-option> </cdk-virtual-scroll-viewport> </mat-select>
对应样式补充(必须给虚拟滚动视口设置固定高度):
.viewport { height: 288px; /* 按最多展示6项计算 6*48px,可按需调整 */ width: 100%; }
2. TS代码修改
- 新增
trackByItem函数,按选项唯一标识复用节点 - 调整
openChange里的滚动触发时机,确保视口初始化完成后再滚动 - 调整选中变更逻辑,直接从
mat-select的事件拿值
修改后TS代码:
// 新增trackBy函数 trackByItem(index: number, item: any[]) { // 用选项的唯一标识(此处为svg文件名)作为追踪key return item[1]; } openChange($event: boolean) { if ($event) { // 加0ms延时确保虚拟滚动视口已完成初始化 setTimeout(() => { const selectedIndex = this.items.findIndex(elem => elem[1] === this.selected[1]); if (selectedIndex > -1) { this.cdkVirtualScrollViewPort.scrollToIndex(selectedIndex); this.cdkVirtualScrollViewPort.checkViewportSize(); } }, 0); } } // 调整选中变更事件逻辑 onSelectionChange(event: MatSelectChange) { this.selected = event.value; }
3. 窗口resize异常修复
如果调整窗口大小后仍有选中值丢失问题,可新增窗口resize监听,主动触发虚拟滚动视口尺寸校验:
@HostListener('window:resize') onWindowResize() { if (this.cdkVirtualScrollViewPort) { this.cdkVirtualScrollViewPort.checkViewportSize(); } }
内容的提问来源于stack exchange,提问作者Labyrinth
相关产品推荐
相关产品推荐

