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

如何在TypeScript中编写支持嵌套对象的通用表格排序函数?

问题描述

我有一个通过对象数组填充数据的HTML表格,表格列对应对象的属性。我希望点击任意列表头时对数据进行排序,但由于表格输入对象包含嵌套对象,难以编写通用排序函数。

示例说明

假设有一个Order接口:

export interface Order {
  date: string;
  paid: boolean;
  customer: {
    name: string;
    address: {
      city: string;
    }
  }
}

我有一个列数据数组:

tableColumns: {colName: string; header: string}[] = [
  {colName: 'date', header: 'Date'},
  {colName: 'paid', header: 'Is paid'},
  {colName: 'customer.name', header: 'Name'},
  {colName: 'customer.address.city', header: 'City'}
]

表格代码如下:

<table>
  <thead>
    <th *ngFor="let col of tableColumns" (click)="sort(col.colName)">{{ col.header }}</th>
  </thead>
  <tbody *ngFor="let o of orders">
    <tr>
      <td>{{ o.date }}</td>
      <td>{{ o.paid }}</td>
      <td>{{ o.customer.name }}</td>
      <td>{{ o.customer.address.city }}</td>
    </tr>
  </tbody>
</table>

我的初始排序方法只能处理非嵌套属性:

sort(colName: string) {
  this.orders.sort((a, b) => a[colName] < b[colName] ? 1 : a[colName] > b[colName] ? -1 : 0)
}

显然该方法仅对date和paid有效,无法处理嵌套对象属性。我目前用if语句做了临时解决方案,但不够优雅,请问是否有办法编写通用的排序方法?

我当前的临时解决方案(并不满意):

sort(colName: string) {
  if (colName === 'customer.name') {
    this.orders.sort((a, b) => a.customer.name < b.customer.name ? 1 : a.customer.name > b.customer.name ? -1 : 0)
  } else {
    this.orders.sort((a, b) => a[colName] < b[colName] ? 1 : a[colName] > b[colName] ? -1 : 0)
  }
}

通用排序方案

1. 编写嵌套属性取值工具函数

先实现一个能解析点分隔路径、获取嵌套对象属性的通用函数,支持任意层级的嵌套:

getNestedValue(obj: any, path: string): any {
  return path.split('.').reduce((current, key) => {
    return current && current[key] !== undefined ? current[key] : undefined;
  }, obj);
}

2. 改造通用排序函数

利用上面的工具函数,就能写出支持嵌套属性的排序方法,同时还可以加入升序/降序切换的优化(可选):

// 新增变量记录当前排序列和方向
currentSortCol: string = '';
sortDirection: 'asc' | 'desc' = 'asc';

sort(colName: string) {
  // 点击同一列时切换排序方向
  if (this.currentSortCol === colName) {
    this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
  } else {
    this.currentSortCol = colName;
    this.sortDirection = 'asc';
  }

  this.orders.sort((a, b) => {
    const valA = this.getNestedValue(a, colName);
    const valB = this.getNestedValue(b, colName);

    // 针对不同类型做适配比较
    if (typeof valA === 'string' && typeof valB === 'string') {
      return this.sortDirection === 'asc' 
        ? valA.localeCompare(valB) 
        : valB.localeCompare(valA);
    }
    if (typeof valA === 'boolean' && typeof valB === 'boolean') {
      const boolValA = valA ? 1 : -1;
      const boolValB = valB ? 1 : -1;
      return this.sortDirection === 'asc' ? boolValA - boolValB : boolValB - boolValA;
    }
    // 数字、日期等类型的比较
    return this.sortDirection === 'asc' 
      ? (valA > valB ? 1 : valA < valB ? -1 : 0) 
      : (valB > valA ? 1 : valB < valA ? -1 : 0);
  });
}

3. 表头排序标识优化(可选)

如果要在表头显示当前排序方向,可修改模板:

<th *ngFor="let col of tableColumns" (click)="sort(col.colName)">
  {{ col.header }}
  <span *ngIf="currentSortCol === col.colName">
    {{ sortDirection === 'asc' ? '↑' : '↓' }}
  </span>
</th>

方案说明

  • getNestedValue通过拆分路径字符串,逐层遍历对象获取属性值,完美适配customer.name、customer.address.city这类嵌套路径。
  • 排序函数中增加类型判断,针对字符串、布尔值等不同类型做适配比较,确保排序逻辑准确。
  • 升序/降序切换属于体验优化,不需要的话可以去掉相关变量和逻辑,只保留核心的嵌套属性比较部分。

内容的提问来源于stack exchange,提问作者ma_po

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 21:15:19