Angular多mat-tabs展示Excel数据时Mat-paginator仅首个标签页生效问题
解决Angular mat-tabs中多标签页mat-paginator仅第一个生效的问题
问题根源
- 所有标签页共用同一个
dataSource实例,且通过ViewChild只能获取到第一个标签页的分页器,切换标签页时始终给数据源绑定第一个分页器,导致其他分页器无法生效。 - 模板中所有分页器使用相同的模板引用变量,无法区分不同标签页的分页器实例。
解决方案
为每个标签页维护独立的数据源和分页器关联,具体实现如下:
1. 组件类修改
import { Component, ViewChildren, QueryList, AfterViewInit } from '@angular/core'; import { MatTableDataSource } from '@angular/material/table'; import { MatPaginator } from '@angular/material/paginator'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements AfterViewInit { allnames: string[] = []; salldata: { [key: string]: any[][] } = {}; // 存储每个标签页独立的数据源和列配置 tabData: Array<{ dataSource: MatTableDataSource<any>, displayedColumns: string[] }> = []; @ViewChildren('userPaginator') paginators!: QueryList<MatPaginator>; ngAfterViewInit(): void { // 分页器列表更新时重新绑定关联关系 this.paginators.changes.subscribe(() => { this.bindAllPaginators(); }); } OnFileChange(event: any) { // 保留原有Excel解析逻辑,解析完成后初始化tabData数组 // 示例:解析完成后更新allnames和salldata // this.allnames = ['Sheet1', 'Sheet2', ...]; // this.salldata = { /* 解析后的表数据 */ }; // 为每个标签页初始化空数据源 this.tabData = this.allnames.map(() => ({ dataSource: new MatTableDataSource(), displayedColumns: [] })); } display(data: any): void { const tabIndex = data.tab.index; const sheetName = data.tab.textLabel; const sheetData = this.salldata[sheetName]; const displayedColumns = sheetData[0]; let tempData: any[] = []; // 转换Excel数据为表格可用格式 for (let i = 0; i < sheetData.length; i++) { const tempRow: any = {}; for (let j = 0; j < sheetData[i].length; j++) { if (sheetData[i][j] !== undefined) { tempRow[displayedColumns[j]] = sheetData[i][j]; } } tempData.push(tempRow); } tempData.shift(); // 移除表头行 // 给当前标签页设置独立数据源和列配置 this.tabData[tabIndex].displayedColumns = displayedColumns; this.tabData[tabIndex].dataSource.data = tempData; // 绑定当前标签页的分页器 this.bindPaginator(tabIndex); } // 绑定单个标签页的分页器 private bindPaginator(index: number): void { const paginator = this.paginators.toArray()[index]; if (paginator) { this.tabData[index].dataSource.paginator = paginator; } } // 批量绑定所有分页器 private bindAllPaginators(): void { this.tabData.forEach((_, index) => this.bindPaginator(index)); } }
2. 模板修改
<input type="file" (change)="OnFileChange($event)" #file > <mat-tab-group mat-align-tabs="start" (selectedTabChange)="display($event)"> <mat-tab *ngFor="let c of allnames; let i = index" label="{{c}}"> <div class="mat-elevation-z8"> <table mat-table [dataSource]="tabData[i].dataSource" style="overflow-x:auto; overflow-y:auto; white-space: nowrap;"> <ng-container *ngFor="let name of tabData[i].displayedColumns;" matColumnDef="{{name}}"> <th mat-header-cell *matHeaderCellDef mat-sort-header style="background-color: #f5f6fa; font-size:100%"> {{name}} </th> <td mat-cell *matCellDef="let dt"> {{dt[name]}} </td> </ng-container> <tr mat-header-row *matHeaderRowDef="tabData[i].displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: tabData[i].displayedColumns;"></tr> </table> <mat-paginator #userPaginator [length]="tabData[i].dataSource.data.length" [pageSizeOptions]="[7,10,100]" showFirstLastButtons></mat-paginator> </div> </mat-tab> </mat-tab-group>
关键改进点
- 每个标签页拥有独立的
MatTableDataSource实例,避免数据源冲突 - 通过
ViewChildren获取所有分页器实例,根据标签索引绑定对应分页器到数据源 - 模板中通过索引关联每个标签页的数据源、列配置和分页器属性
内容的提问来源于stack exchange,提问作者Chethan K
相关产品推荐
相关产品推荐

