You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular Material折叠面板在虚拟滚动中无法正常展开的问题

解决Angular CDK虚拟滚动与Material折叠面板展开异常的问题

这个问题我太熟了!当Angular CDK虚拟滚动遇上Material折叠面板时,经常会出现点击展开却只有一点点高度变化的情况,核心原因是虚拟滚动没察觉到折叠面板的高度发生了动态变化——它默认依赖itemSize的固定值来计算布局,面板展开后实际高度变了,但虚拟滚动视图没主动更新。下面给你具体的解决步骤:

1. 获取虚拟滚动视图实例

首先在组件类里,通过ViewChild获取CdkVirtualScrollViewport的实例,这样我们才能调用它的更新方法来重新计算高度:

import { Component, ViewChild } from '@angular/core';
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';

@Component({
  selector: 'app-your-component',
  templateUrl: './your-component.component.html'
})
export class YourComponent {
  @ViewChild(CdkVirtualScrollViewport) private viewport!: CdkVirtualScrollViewport;

  // 面板展开时触发的方法
  onPanelOpened(): void {
    // 延迟执行,确保DOM已经完成高度更新
    setTimeout(() => {
      this.viewport?.checkViewportSize();
      this.viewport?.measureRenderedContentSize();
    }, 0);
  }

  // 面板折叠时触发的方法
  onPanelClosed(): void {
    setTimeout(() => {
      this.viewport?.checkViewportSize();
      this.viewport?.measureRenderedContentSize();
    }, 0);
  }
}

2. 给折叠面板绑定展开/折叠事件

修改你的模板,给每个mat-expansion-panel绑定opened和closed事件,触发上面写的更新方法:

<div class="container">
  <mat-card>
    <mat-card-title>
      <span class="panelItem">Id</span>
      <span class="secondPanelItem">Name</span>
      <span class="lastPanelItem">Version</span>
    </mat-card-title>
  </mat-card>
  <cdk-virtual-scroll-viewport itemSize="50" class="viewport">
    <mat-accordion>
      <ng-container *cdkVirtualFor="let description of allDescriptions">
        <mat-expansion-panel 
          (opened)="onPanelOpened()" 
          (closed)="onPanelClosed()">
          <mat-expansion-panel-header>
            <mat-panel-title>
              <span class="panelItem">{{description.id}}</span>
              <span class="secondPanelItem">{{description.name}}</span>
              <span class="lastPanelItem">{{description.version}}</span>
            </mat-panel-title>
          </mat-expansion-panel-header>
          <!-- 这里放你的面板展开内容 -->
          <div class="panel-content">
            {{description.content}}
          </div>
        </mat-expansion-panel>
      </ng-container>
    </mat-accordion>
  </cdk-virtual-scroll-viewport>
</div>

3. 额外注意事项

  • itemSize="50"要尽量和折叠面板的实际高度一致,这样虚拟滚动的初始布局计算会更准确;
  • 如果你的面板内容高度差异很大,也可以考虑使用cdkVirtualForTrackBy来优化渲染性能;
  • 用setTimeout是因为面板展开/折叠后,DOM高度的更新是异步的,延迟执行能确保虚拟滚动拿到最新的高度值再重新计算。

内容的提问来源于stack exchange,提问作者irudji

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:58:24