Angular Material数据表多列排序问题:无法保留前置排序状态
Angular Material 数据表多列排序实现
方案一:使用官方自带的多列排序(按住Shift键点击表头)
Angular Material 的 MatSort 原生支持多列排序,默认通过按住Shift键点击表头来累加排序条件,不会清除之前的排序规则。你只需做以下调整:
1. 模板配置
在 mat-table 标签上指定多列排序的触发修饰键(默认就是shift,也可设为ctrl/alt):
<mat-table [dataSource]="dataSource" matSort [matSortMultiSortKey]="'shift'"> <!-- 列定义示例 --> <ng-container matColumnDef="project.isActive"> <mat-header-cell *matHeaderCellDef mat-sort-header>项目状态</mat-header-cell> <mat-cell *matCellDef="let item">{{item.project.isActive ? '激活' : '未激活'}}</mat-cell> </ng-container> <!-- 其他列... --> </mat-table>
2. 组件代码保留原有逻辑
你现有的数据源配置无需大幅修改,确保 MatSort 实例正确绑定即可:
import { MatTableDataSource, MatSort } from '@angular/material/table'; // 组件类内代码 this.dataSource = new MatTableDataSource(yourData); this.dataSource.sortingDataAccessor = (item, property) => { switch(property) { case 'project.isActive': return item.project.isActive; case 'project.start': return item.project.start; default: return item[property]; } }; this.dataSource.sort = sort; // sort为通过@ViewChild获取的MatSort实例
操作时按住Shift点击不同表头,就能基于前一列的排序结果实现多列排序。
方案二:自定义无需修饰键的多列排序(点击直接累加)
如果希望无需按住Shift,直接点击表头就能累加排序条件,可以通过重写数据源的sortData方法,手动维护排序规则数组实现:
1. 组件内实现多列排序逻辑
import { MatTableDataSource, MatSort, Sort, SortDirection } from '@angular/material/table'; import { ViewChild, AfterViewInit } from '@angular/core'; export class YourComponent implements AfterViewInit { dataSource = new MatTableDataSource<any>([]); @ViewChild(MatSort) sort!: MatSort; // 保存多列排序规则 private sortCriteria: {id: string, direction: SortDirection}[] = []; ngAfterViewInit(): void { this.dataSource.sort = this.sort; this.initMultiSort(); } private initMultiSort(): void { // 监听表头排序事件 this.sort.sortChange.subscribe((sortEvent: Sort) => { const existingIndex = this.sortCriteria.findIndex(c => c.id === sortEvent.active); if (existingIndex !== -1) { // 切换已有列的排序方向,空方向则移除该规则 this.sortCriteria[existingIndex].direction = sortEvent.direction === 'asc' ? 'desc' : sortEvent.direction === 'desc' ? '' : 'asc'; if (this.sortCriteria[existingIndex].direction === '') { this.sortCriteria.splice(existingIndex, 1); } } else { // 添加新的排序规则(仅当方向不为空时) if (sortEvent.direction) { this.sortCriteria.push({id: sortEvent.active, direction: sortEvent.direction}); } } // 重写数据源的排序逻辑 this.dataSource.sortData = (data: any[], sort: MatSort) => { return this.multiColumnSort(data, this.sortCriteria); }; // 手动触发数据更新 this.dataSource._updateChangeSubscription(); }); } // 多列排序核心逻辑 private multiColumnSort(data: any[], criteria: {id: string, direction: SortDirection}[]): any[] { if (!criteria.length) return data; return [...data].sort((a, b) => { for (const criterion of criteria) { const valueA = this.getSortValue(a, criterion.id); const valueB = this.getSortValue(b, criterion.id); if (valueA !== valueB) { return criterion.direction === 'asc' ? (valueA < valueB ? -1 : 1) : (valueA < valueB ? 1 : -1); } } return 0; }); } // 复用原有的排序值获取逻辑 private getSortValue(item: any, property: string): any { switch(property) { case 'project.isActive': return item.project.isActive; case 'project.start': return item.project.start; default: return item[property]; } } }
2. 模板配置
模板只需保留基础的matSort和mat-sort-header即可:
<mat-table [dataSource]="dataSource" matSort> <!-- 列定义... --> <mat-header-cell *matHeaderCellDef mat-sort-header>项目状态</mat-header-cell> <!-- 其他列... --> </mat-table>
这样每次点击表头,都会将该列添加到排序规则中(重复点击切换方向,再次点击空方向则移除),排序结果会基于所有已添加的列依次生效。
内容的提问来源于stack exchange,提问作者Fardin Noman
相关产品推荐
相关产品推荐

