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
相关产品推荐
相关产品推荐

