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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 10:00:24