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

Angular自定义表格多小数点编号排序异常求助(RxJS+Lodash)

解决Angular自定义表格多小数点编号排序异常问题

问题现状

当前使用Lodash orderBy 和RxJS ReplaySubject 实现的Angular表格排序,对字符串、普通数字类型排序正常,但多小数点格式的编号(如Requirement ID)排序结果不符合预期:

当前错误排序结果:

4.1.13
4.1.19
4.1.25
4.1.7
4.1.8
4.3.2
4.3.3
4.4.2

期望排序结果:

4.1.7
4.1.8
4.1.13
4.1.19
4.1.25
4.3.2
4.3.3
4.4.2

问题原因

Lodash orderBy 默认按字符串字典序排序,多小数点编号作为字符串比较时,会逐字符比对ASCII值:比如"4.1.13"的第4个字符是1,而"4.1.7"的第4个字符是7,ASCII值1 < 7,所以"4.1.13"会排在"4.1.7"前面,不符合层级编号的排序逻辑。

解决方案

自定义针对多小数点编号的排序规则:将编号拆分为数字数组,逐位比较数字大小,而非字符串字典序。以下是两种实现方式:

方式1:针对特定字段的自定义排序函数

在DTable.ts中添加辅助比较函数,并修改排序逻辑:

import { Directive , EventEmitter , Input , Output , OnInit , OnChanges, DoCheck, IterableDiffers, IterableDiffer } from '@angular/core';
import { ReplaySubject } from "rxjs";
import * as _ from "lodash";

export interface SortEvent {
  sortBy: string|string[];
  sortOrder: string
}

@Directive({
  selector: '<table [mxData]',
  exportAs: `mxDataTable`
})

export class DTableG implements OnChanges , OnInit, DoCheck  {

  private diff: IterableDiffer<any>;
  public onPageChange = new EventEmitter<PageEvent>();
  public data: any[] = []; // 补充组件内存储排序后数据的属性

  @Output() public onSortChange = new ReplaySubject<SortEvent>(1);
  @Input("mfSortBy") public sortBy: string|string[] = "";
  @Input("mfSortOrder") public sortOrder = "asc";
  @Input("mxData") public mxData : any[] = [];

  // 自定义多小数点编号比较函数
  private compareDotSeparatedIds(a: string, b: string): number {
    const aParts = a.split('.').map(part => isNaN(Number(part)) ? 0 : Number(part));
    const bParts = b.split('.').map(part => isNaN(Number(part)) ? 0 : Number(part));
    const maxLength = Math.max(aParts.length, bParts.length);
    
    for (let i = 0; i < maxLength; i++) {
      const aVal = aParts[i] || 0;
      const bVal = bParts[i] || 0;
      if (aVal !== bVal) {
        return aVal - bVal;
      }
    }
    return 0;
  }

  ngOnChanges() {        
    if (this.sortBy === 'requirementId') {
      // 针对多小数点ID使用自定义排序
      this.data = [...this.mxData].sort((itemA, itemB) => {
        const compareResult = this.compareDotSeparatedIds(itemA.requirementId, itemB.requirementId);
        return this.sortOrder === 'asc' ? compareResult : -compareResult;
      });
    } else {
      // 原有逻辑处理普通字符串/数字
      this.data = _.orderBy(this.mxData, this.sortBy, [this.sortOrder]);
    }
  }

  public setSort(sortBy: string|string[], sortOrder: string): void {
    if (this.sortBy !== sortBy || this.sortOrder !== sortOrder) {
        this.sortBy = sortBy;
        this.sortOrder = _.includes(["asc","desc"], sortOrder) ? sortOrder : "asc";
        this.onSortChange.next({sortBy: sortBy, sortOrder: sortOrder});  
     }
  }
}

方式2:通用化Lodash迭代器(支持多字段排序)

如果需要支持多个多小数点字段的排序,可以通过修改Lodash orderBy 的迭代器,将目标字段转换为数字数组后排序:

ngOnChanges() {        
  // 将排序字段转换为迭代器:针对多小数点字段返回数字数组,其他字段保持原字段名
  const iteratees = Array.isArray(this.sortBy) ? this.sortBy : [this.sortBy];
  const sortedIteratees = iteratees.map(key => {
    // 可扩展需要处理的多小数点字段列表
    if (['requirementId', 'otherDotIdField'].includes(key as string)) {
      return (item: any) => item[key].split('.').map(part => isNaN(Number(part)) ? 0 : Number(part));
    }
    return key;
  });

  this.data = _.orderBy(this.mxData, sortedIteratees, [this.sortOrder]);
}

注意事项

  • 辅助函数中添加了isNaN判断,避免非数字格式的编号导致排序异常
  • 如果需要支持动态识别多小数点字段,可以通过正则表达式匹配字段值格式(如/^\d+(\.\d+)+$/)来自动触发自定义排序

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 20:35:27