Ant Design Table 多列排序(multiple sorter)完全指南:优先级配置、compare 函数与源码原理
2026/9/20 23:10:31 网站建设 项目流程
  • 前端
  • UI组件
  • 设计系统

【免费下载链接】ant-design

An enterprise-class UI design language and React UI library

项目地址:https://gitcode.com/gh_mirrors/ant/ant-design
点击查看免费下载

多列排序是 Ant Design Table 在处理"先按 A 列、再按 B 列"这类复合排序需求时的官方能力,通过column.sorter.multiple字段声明各列的排序优先级,配合compare函数完成本地复合排序。本文以仓库中的 multiple-sorter 官方示例 为骨架,完整覆盖配置语法、交互行为、onChange回调形态,并结合 useSorter.tsx 源码与 Table.sorter.test.tsx 测试用例,讲透多列排序从声明到生效的完整链路。

什么是多列排序

Ant Design Table 的单列排序只需要给列配置sorter函数即可,但业务中经常出现"语文成绩相同再按数学成绩排"的复合排序诉求。官方为此在column.sorter上开放了对象形态的配置:

sorter: { compare: (a, b) => a.chinese - b.chinese, // 排序逻辑 multiple: 3, // 多列排序优先级 }

其中:

  • multiple:多列排序的优先级权重,数字越大优先级越高,最先参与排序;
  • compare:与单列排序相同的比较函数,返回负数表示 a 排在前面、正数表示 b 排在前面、0 表示相等;
  • 两者均可独立省略:不写compare时,该列只参与多列排序的交互(可被点选为排序列),但不实际改变数据顺序。

multiple字段的完整类型定义位于 ColumnType.sorter:

sorter?: | boolean | CompareFn<RecordType> | { compare?: CompareFn<RecordType>; /** Config multiple sorter order priority */ multiple?: number; };

官方示例:成绩表的多列排序

官方 demo multiple-sorter.tsx 用一张包含语文、数学、英语三科成绩的表格演示了完整的用法。先定义三列可排序列,并为它们声明不同的优先级——语文为 3(最高)、数学为 2、英语为 1:

const columns: TableColumnsType<DataType> = [ { title: 'Name', dataIndex: 'name', }, { title: 'Chinese Score', dataIndex: 'chinese', sorter: { compare: (a, b) => a.chinese - b.chinese, multiple: 3, }, }, { title: 'Math Score', dataIndex: 'math', sorter: { compare: (a, b) => a.math - b.math, multiple: 2, }, }, { title: 'English Score', dataIndex: 'english', sorter: { compare: (a, b) => a.english - b.english, multiple: 1, }, }, ];

测试数据刻意构造了有歧义的场景:John Brown、Jim Green、Joe Black 三人的语文成绩都是 98,此时仅凭语文成绩无法决出先后,就需要依赖数学(甚至英语)成绩作为次级排序依据:

const data: DataType[] = [ { key: '1', name: 'John Brown', chinese: 98, math: 60, english: 70 }, { key: '2', name: 'Jim Green', chinese: 98, math: 66, english: 89 }, { key: '3', name: 'Joe Black', chinese: 98, math: 90, english: 70 }, { key: '4', name: 'Jim Red', chinese: 88, math: 99, english: 89 }, ];

表格本体只需要两行代码,排序状态与数据重排由 Table 内部自动完成:

const App: React.FC = () => <Table columns={columns} dataSource={data} onChange={onChange} />;

运行时交互为:依次点击"Chinese Score""Math Score""English Score"三个表头,即可逐步叠加排序条件;表头会同时显示多列各自的升/降序箭头,点击同一列会在"升序 → 降序 → 取消"之间循环切换。

sorter 的三种配置形态

结合 ColumnType.sorter 类型定义 与 useSorter.tsx 中的 getSortFunction,sorter实际支持三种写法:

形态写法行为
布尔值sorter: true仅开启排序交互,不排序数据(服务端排序场景)
函数sorter: (a, b) => a.math - b.math单列本地排序
对象sorter: { compare, multiple }可配置多列排序优先级;comparemultiple均可省略

源码中的getSortFunction对函数形态和对象形态做了归一化处理:函数直接返回,对象则取出其compare属性,两者都取不到时返回false(表示该列没有可执行的真实排序逻辑,仅保留交互)。

优先级是如何生效的:读 useSorter.tsx 源码

多列排序的"优先级"不是 UI 层面的展示概念,而是真实参与数据重排的算法。核心逻辑在 getSortData 函数,其执行链路可以拆解为三步。

第一步:按优先级降序排列排序状态。所有处于激活状态的排序列被收集为SortState数组,每个状态携带multiplePriority字段,然后按优先级从大到小排序:

const innerSorterStates = sortStates .slice() .sort((a, b) => (b.multiplePriority as number) - (a.multiplePriority as number));

multiplePriority由 getMultiplePriority 从列的sorter.multiple中提取,数字越大排在越前面。

第二步:逐列调用 compare 函数。对每条记录,按优先级从高到低依次执行各列的compare,只要某一列的比较结果不为 0,就立即以该结果决定两条记录的先后并跳出循环;只有所有列都比完仍为 0 时,才认为两条记录相等、保持原顺序:

for (let i = 0; i < runningSorters.length; i += 1) { const compareResult = compareFn(record1, record2, sortOrder); if (compareResult !== 0) { return sortOrder === ASCEND ? compareResult : -compareResult; } }

注意降序的处理方式:compare函数始终按"升序语义"编写(a 比 b 小返回负数),实际方向由sortOrder决定,降序时对结果取反即可,无需为每个方向各写一份比较逻辑。

第三步:递归处理子表数据。如果数据行带有子记录(树形表格),会以同样的sortStates递归排序每一层的子数据,保证树形结构的每一级都遵循相同的复合排序规则。

只开交互不做排序:省略 compare 的用法

官方文档特别强调:"You can also leave it empty to use the interactive only"——即列可以只配置multiple而不提供compare函数。此时该列会正常显示排序箭头、可以被点选加入多列排序状态,但getSortFunction返回false,getSortData 中的 runningSorters 过滤会把它剔除出实际排序环节,数据顺序不受影响。

这一形态主要用于服务端排序场景:前端只负责收集并上报用户选择了哪些列、什么方向,真正的排序由后端根据参数执行。配合onChange回调拿到完整的排序条件数组即可。

读取排序结果:onChange 的 sorter 参数

demo 中注册了 onChange 回调:

const onChange: TableProps<DataType>['onChange'] = (pagination, filters, sorter, extra) => { console.log('params', pagination, filters, sorter, extra); };

onChange的四个参数分别是分页信息、筛选条件、排序结果与附加信息({ currentDataSource, action })。与单列排序最大的区别在于:多列排序激活后,sorter参数是一个数组,每项包含{ column, order, field, columnKey },数组顺序与激活顺序相关。

这一行为由 generateSorterInfo 决定:所有带sortOrder的排序状态被映射为SorterResult后,如果结果多于一条就返回数组,只有一条或没有时返回单个对象或空对象。该行为在 Table.sorter.test.tsx 的 "multiple sort should pass array sorter as onChange param" 用例 中得到了专门验证。此外,为了兼容旧版本,当排序状态存在但没有激活任何排序时,会返回最后一个状态的列信息且column置为undefined

交互细节与配套配置

多列排序可以与 Table 的其它排序配置自由组合:

  • 点击循环:点击表头按"升序 → 降序 → 取消"循环,逻辑在 nextSortDirection 中实现;可通过列的sortDirections或 Table 级sortDirections(默认['ascend', 'descend'])限制可用方向。
  • 受控排序:配合sortOrder/defaultSortOrder可在多列模式下声明初始或受控的排序状态。Table.sorter.test.tsx 的 "controlled multiple group" 用例 演示了多个列同时通过sortOrder受控、且包含嵌套子列(children)的多列排序场景,其中"Math Score"列本身带子列但自身也被激活为排序列。
  • 排序提示showSorterTooltip默认开启,悬停表头会提示下一次点击将触发的方向(升序/降序/取消),文案来自 Table 的 locale(triggerAsctriggerDesccancelSort)。
  • 状态叠加规则:triggerSorter 中,当点击的列具备multiple优先级、且当前已有激活的多列排序状态时,新状态会被追加进排序数组(旧的同名状态先被剔除);反之,如果点击的列是普通单列排序,则会清空所有已有多列状态、退化为单列排序。

注意事项:单列与多列排序不要混用

混合使用单列排序(sorter为布尔或函数)与多列排序(sorter.multiple)会让优先级语义变得不可预期。测试 "invalidate mix with single & multiple sorters" 用例 专门覆盖了"一个列是sorter: { multiple: 1 },另一个列是普通排序"的混合场景,用于确认此类配置下的行为边界。实际开发中建议:要么整张表统一走单列排序,要么统一为多列排序(所有可排序列都配置multiple),避免混合引发排序状态互相覆盖的困惑。

小结

Ant Design Table 的多列排序围绕三个要点展开:用multiple声明优先级、用compare提供比较逻辑、用onChange接收排序结果数组。理解 useSorter.tsx 中"按优先级降序排列、逐列比较、首列非 0 即定序"的算法后,即使面对语文同分、数学同分的多级排序业务,也能准确预判表格的最终排列结果。完整的可运行示例见 multiple-sorter.tsx,排序 API 的完整参数说明可查阅 Table 组件文档。

  • 前端
  • UI组件
  • 设计系统

【免费下载链接】ant-design

An enterprise-class UI design language and React UI library

项目地址:https://gitcode.com/gh_mirrors/ant/ant-design
点击查看免费下载
上一篇:3步掌握IPATool:从App Store高效下载iOS应用包
下一篇:usearch的开源可持续性:赞助与捐赠支持方式

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询