Angular Mat Table调整列时如何避免单元格内组件重新初始化?
问题
每次调整Mat Table的列时,表格单元格内的所有组件都会重新加载,这会引发两个问题:
- 组件状态丢失
- 所有组件同时重加载导致性能低下
该问题不会出现在列表或原生<table>表格中,目前已有可复现的示例及对应预览图。
已尝试的解决方案
试过给*ngFor添加trackBy函数,但没有效果,该方案不适用于此场景:因为列是通过字符串标识的,且列表和原生表格场景下无需使用trackBy即可避免组件重新触发。目前没有找到相关问题的解决资料,现有资料大多是介绍如何修改matData避免表格重渲染,但该问题触发时甚至没有修改表格数据。
需求场景
开发了一个Column Filter组件,需要在表格的第二行表头中每列都引入该组件。该列筛选组件支持用户为每列设置不同的筛选字符串,还提供选项菜单允许用户设置匹配规则:包含字符串、不包含、开头匹配等。另外还在适配不同数据类型:如果是日期列,用户无需在输入框键入内容,而是通过日历选择日期范围,之后还可设置匹配规则为范围之内、范围之外、早于指定日期等,有对应的列筛选组件示例可参考。
这些组件的初始化需要一定时间,列数少于3个时影响可以忽略,但如果表格有12列且每列都有筛选组件,每次移动或删除列都会产生300ms以上的延迟。
理想解决方案
理想情况下,Mat Table调整列顺序时无需销毁并重建单元格内的所有组件。
可行的替代方案
- 优化Column Filter组件的加载速度
- 经测试,移除列筛选组件中的mat-menus可以大幅提升加载速度,因此可以尝试使用替代组件、自行实现菜单功能或实现菜单按需加载。
- 最终为mat菜单实现了lazy loading逻辑,效果很好:12列Mat Table的调整延迟从300ms区间降低到了40ms以内。
- 经测试,移除列筛选组件中的mat-menus可以大幅提升加载速度,因此可以尝试使用替代组件、自行实现菜单功能或实现菜单按需加载。
// 懒加载代码 <button [matMenuTriggerFor]="menu" (click)="showMenu = true"/> <mat-menu #menu="matMenu"> <div *ngIf="showMenu"> ... </div> </mat-menu>
- 尝试逐次加载列筛选组件而非一次性全部加载(该方案可行性较低)
- 尝试基于cdkTable实现相关功能
- 使用原生
<table>替代Mat Table- 最有效的替代方案是直接弃用Mat Table,但并不建议这么做:如果已经接入了Mat Table的分页器、matData数据处理、数据筛选、样式格式化等能力,切换方案需要从零开发所有相关能力。但如果要追求更高性能可能不得不这么做。Angular Material组件外观精美,基础功能表现稳定,但如果要在此基础上添加自定义复杂功能,往往会出现适配问题。
内容的提问来源于stack exchange,提问作者Hunter
相关产品推荐
相关产品推荐

