如何在Angular Mat-table的TypeScript中获取列标题宽度?
解决Angular Mat-Table列宽度获取与过滤器宽度匹配问题
问题说明
需要获取Angular mat-table中每一列标题的宽度,用来设置对应列上方过滤器(mat-form-field)的宽度,但使用getElementById().clientWidth的方法无效。
解决方案
- 给每个表头单元格(
mat-header-cell)添加与列名对应的唯一id,确保能精准定位DOM元素 - 在
ngAfterViewInit生命周期钩子中获取列宽度(此时DOM已完全渲染完成) - 存储列宽度数据,直接绑定到过滤器的样式属性上
- 监听窗口
resize事件,实时更新列宽度,保证过滤器与列宽度同步
修改后的TypeScript代码
import { CommonModule } from '@angular/common'; import { Component, ViewChild, AfterViewInit, HostListener } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator'; import { MatSort, MatSortModule } from '@angular/material/sort'; import { MatTableModule } from '@angular/material/table'; import { MatInputModule } from '@angular/material/input'; export interface PeriodicElement { name: string; position: number; weight: number; symbol: string; } const ELEMENT_DATA: PeriodicElement[] = [ { position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H' }, { position: 2, name: 'Helium', weight: 4.0026, symbol: 'He' }, { position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li' }, { position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be' }, { position: 5, name: 'Boron', weight: 10.811, symbol: 'B' }, { position: 6, name: 'Carbon', weight: 12.0107, symbol: 'C' }, { position: 7, name: 'Nitrogen', weight: 14.0067, symbol: 'N' }, { position: 8, name: 'Oxygen', weight: 15.9994, symbol: 'O' }, { position: 9, name: 'Fluorine', weight: 18.9984, symbol: 'F' }, { position: 10, name: 'Neon', weight: 20.1797, symbol: 'Ne' }, ]; @Component({ selector: 'table-basic-example', styleUrl: 'table-basic-example.css', templateUrl: 'table-basic-example.html', standalone: true, imports: [ MatFormFieldModule, MatTableModule, MatSortModule, MatPaginatorModule, FormsModule, ReactiveFormsModule, CommonModule, MatInputModule, ], }) export class TableBasicExample implements AfterViewInit { displayedColumns: string[] = ['position', 'name', 'weight', 'symbol']; dataSource = ELEMENT_DATA; ngModel: any = {}; filteredColumn: string; columnWidths: Record<string, string> = {}; @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; ngAfterViewInit(): void { this.calculateColumnWidths(); } @HostListener('window:resize') onWindowResize() { this.calculateColumnWidths(); } calculateColumnWidths(): void { this.displayedColumns.forEach(column => { const headerElement = document.getElementById(`header-${column}`); if (headerElement) { this.columnWidths[column] = `${headerElement.clientWidth}px`; } }); } applyFilter(event: Event, value?: any, columnName?: any) {} }
修改后的HTML代码
<mat-form-field [style.width]="columnWidths[column]" *ngFor="let column of displayedColumns; index as i" appearance="outline" > <mat-label>{{column}}</mat-label> <input matInput [(ngModel)]="ngModel[column]" (keyup)="applyFilter($event, ngModel[column], column)" #input /> </mat-form-field> <table mat-table [dataSource]="dataSource" class="mat-elevation-z8"> <!-- Position Column --> <ng-container matColumnDef="position"> <th id="header-position" mat-header-cell *matHeaderCellDef>No.</th> <td mat-cell *matCellDef="let element">{{element.position}}</td> </ng-container> <!-- Name Column --> <ng-container matColumnDef="name"> <th id="header-name" mat-header-cell *matHeaderCellDef>Name</th> <td mat-cell *matCellDef="let element">{{element.name}}</td> </ng-container> <!-- Weight Column --> <ng-container matColumnDef="weight"> <th id="header-weight" mat-header-cell *matHeaderCellDef>Weight</th> <td mat-cell *matCellDef="let element">{{element.weight}}</td> </ng-container> <!-- Symbol Column --> <ng-container matColumnDef="symbol"> <th id="header-symbol" mat-header-cell *matHeaderCellDef>Symbol</th> <td mat-cell *matCellDef="let element">{{element.symbol}}</td> </ng-container> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> </table>
关键说明
- 给表头单元格设置
header-列名格式的id,避免与页面其他元素id冲突 - 选择
ngAfterViewInit生命周期计算宽度,确保DOM已完全渲染,能正确获取元素尺寸 - 添加窗口resize监听,当窗口大小变化时自动重新计算列宽度,保证过滤器与列宽度始终匹配
- 将宽度数据存储在
columnWidths对象中,直接绑定到过滤器的style.width属性,比重复调用函数更高效
内容的提问来源于stack exchange,提问作者Silver Origami
相关产品推荐
相关产品推荐

