- 前端
- UI组件
- 设计系统
【免费下载链接】ant-design
An enterprise-class UI design language and React UI library
多列排序是 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 } | 可配置多列排序优先级;compare与multiple均可省略 |
源码中的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(triggerAsc、triggerDesc、cancelSort)。 - 状态叠加规则: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
相关推荐
ant-design Table 组件列筛选(Filter)与排序(Sorter)完全指南:从配置到源码实现
ant design Table 组件列筛选(Filter)与排序(Sorter)完全指南:从配置到源码实现 本指南以 ant design Table 组件为
UI组件前端设计系统Ant Design Table 列筛选(filters)与排序(sorter)完整实战指南
Ant Design Table 列筛选(filters)与排序(sorter)完整实战指南 Ant Design 的 Table 组件内置了列级筛选与排序能力
前端UI组件设计系统Claude Code Router 接入 DeepSeek 完整指南:五步配好模型网关,附日志排查法
Claude Code Router 接入 DeepSeek 完整指南:五步配好模型网关,附日志排查法 Claude Code Router CCR 是一个本地
前端UI组件设计系统
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考