Angular Material Sort 组件 API 全解析:matSort 指令与 mat-sort-header 表头排序实战指南
Angular Material Sort 组件 API 全解析matSort 指令与 mat-sort-header 表头排序实战指南【免费下载链接】componentsComponent infrastructure and Material Design components for Angular项目地址: https://gitcode.com/GitHub_Trending/co/components导读angular/material/sort是 Angular Material 提供的一套面向表格数据的排序基础设施由matSort容器指令与mat-sort-header表头组件协同工作为开发者提供统一的排序状态管理、方向循环、键盘操作与无障碍ARIA支持。本文以本仓库生成的 API 报告 goldens/material/sort/index.api.md 为骨架结合 sort.ts、sort-header.ts 等真实源码深入展开读完你将掌握该模块全部公开 API 的语义、内部排序状态机的实现原理以及如何在mat-table中落地一个可访问、可扩展的排序表格。一、模块概览从 API 报告读懂模块边界API 报告由 API Extractor 生成是本模块对外契约的权威来源。从 goldens/material/sort/index.api.md 可以看出angular/material/sort共对外导出 10 个公开符号可划分为四类类别公开符号作用指令MatSort容器指令持有全部表头注册表与排序状态组件MatSortHeader表头组件展示排序箭头并响应点击/键盘配置与状态MatSortDefaultOptions、MAT_SORT_DEFAULT_OPTIONS、MatSortable、Sort、SortDirection、SortHeaderArrowPosition类型定义与全局配置令牌模块与国际化MatSortModule、MatSortHeaderIntl已废弃模块声明与标签定制入口模块声明可在 sort-module.ts 中确认MatSortModule导入并导出MatSort与MatSortHeader同时转发导出BidiModule来自angular/cdk/bidi用于支持 RTL 场景下箭头方向的自动翻转。NgModule({ imports: [MatSort, MatSortHeader], exports: [MatSort, MatSortHeader, BidiModule], }) export class MatSortModule {}版本提示MatSortHeaderIntl 已废弃API 报告明确标注MatSortHeaderIntl为public deprecated。查看源码 sort-header-intl.ts其 JSDoc 给出更精确的说明deprecated No longer used, will be removed.计划在 23.0.0 移除breaking-change 23.0.0。该服务仅保留一个readonly changes: Subjectvoid流已不再参与表头标签的渲染逻辑——当前版本表头动作描述改用sortActionDescription输入属性驱动见下文无障碍章节因此新代码无需再依赖此服务。二、MatSort 容器指令排序状态的“唯一事实来源”MatSort以属性指令形式使用选择器为[matSort]、exportAs: matSort宿主元素自动获得mat-sort类见 sort.ts。它负责三件事注册/注销表头、计算下一次排序方向、对外广播排序变更事件。2.1 核心输入与输出API 报告给出了完整的输入别名映射与源码一一对应API 报告成员模板绑定别名类型/默认值语义activematSortActivestring当前激活排序列的 idstartmatSortStartSortDirection默认asc首次排序时的起始方向directionmatSortDirectionSortDirection默认当前排序方向getter/setterdisableClearmatSortDisableClearbooleanbooleanAttribute转换是否禁止通过循环方向清除排序disabledmatSortDisabledboolean默认false是否禁用整个排序容器sortChangematSortChange输出EventEmitterSort用户改变排序状态时触发两点值得注意active、start未加转换函数disableClear、disabled使用booleanAttribute转换源码 sort.ts因此matSortDisableCleartrue与[matSortDisableClear]true写法等价direction的 setter 会在开发模式下ngDevMode校验非法值仅接受asc、desc或空字符串否则抛出getSortInvalidDirectionErrorsort-errors.ts 中定义为${direction} is not a valid sort direction (asc or desc).。此外MatSort还对外暴露一个initialized: Observablevoid在ngOnInit时通过ReplaySubject(1)发出供需要等待排序容器就绪后再读取状态的逻辑订阅sort.ts。2.2 内部状态流_stateChanges源码中_stateChanges new Subjectvoid()与ngOnChanges挂钩任何输入属性变化都会触发该流发出事件ngOnDestroy时_stateChanges与_initializedStream均被 completesort.ts。MatSortHeader在ngOnInit中订阅merge(this._sort._stateChanges, this._sort.sortChange)并调用markForCheck()从而保证容器属性变化时所有表头能同步刷新箭头与样式sort-header.ts。三、排序状态机方向循环与清除逻辑3.1 sort() 的两种分支MatSort.sort(sortable)是排序的核心入口其行为分两种情况sort.ts切换到新列若active ! sortable.id直接以该列的start若未设置则回退到容器的start作为新方向继续点击当前列调用getNextSortDirection取循环中的下一个方向。无论哪种情况最终都会sortChange.emit({active, direction})发出Sort对象{active: string; direction: SortDirection}。3.2 getNextSortDirection 与方向循环方向循环由内部函数getSortDirectionCycle构造sort.tsfunction getSortDirectionCycle(start: SortDirection, disableClear: boolean): SortDirection[] { let sortOrder: SortDirection[] [asc, desc]; if (start desc) { sortOrder.reverse(); // 起始为 desc 时循环变为 [desc, asc] } if (!disableClear) { sortOrder.push(); // 允许清除时追加空方向 } return sortOrder; }可见默认循环为[asc, desc, ]即第三次点击清除排序。getNextSortDirection在循环中定位当前方向的下一个索引越界则回绕到 0sort.ts。清除开关的优先级链是sortable.disableClear ?? this.disableClear ?? !!this._defaultOptions?.disableClear即单个表头的disableClear优先于容器的matSortDisableClear最后才是全局默认配置。3.3 register / deregister 与 id 约束容器通过Mapstring, MatSortable维护注册表register在开发模式下校验 id 非空且不重复违反时分别抛出getSortHeaderMissingIdError或getSortDuplicateSortableIdErrorsort.tsderegister按 id 从 Map 删除由表头在ngOnDestroy时调用。MatSortable接口id、start、disableClear正是表头注册时向容器提交的“契约”。四、MatSortHeader 表头组件交互、渲染与无障碍MatSortHeader是组件而非指令选择器[mat-sort-header]通过投影ng-content包裹表头内容模板见 sort-header.html。4.1 输入属性与默认值属性类型/默认值说明id别名mat-sort-headerstring列唯一标识在CdkColumnDef/mat-table内自动回退为列名arrowPositionSortHeaderArrowPosition默认after箭头位于文本之后before则在前startSortDirection覆盖容器matSortStart仅作用于本表头disabledboolean默认falsebooleanAttribute禁用本表头disableClearbooleanbooleanAttribute覆盖容器matSortDisableClearsortActionDescriptionstring默认Sort排序按钮的无障碍描述其中id的自动回退逻辑在ngOnInit中实现if (!this.id this._columnDef) { this.id this._columnDef.name; }_columnDef通过inject(CdkColumnDef, {optional: true})获取这也是为什么在mat-table表头中可以不写mat-sort-header值sort-header.ts。4.2 交互与键盘支持宿主元素绑定sort-header.ts(click)_toggleOnInteraction()未禁用时调用_sort.sort(this)并基于排序状态计算_recentlyCleared用于箭头清除动画(keydown)_handleKeydown($event)SPACE或ENTER键触发排序并preventDefault()阻止滚动(mouseleave)_recentlyCleared.set(null)重置清除动画状态。_isDisabled()返回this._sort.disabled || this.disabled即容器级与表头级禁用取并集。注意模板中tabindex与rolebutton均放在内层.mat-sort-header-container上而非th本身——源码注释解释了这是为了规避 NVDA 在th上设置tabindex导致的键盘导航 bugsort-header.html。4.3 箭头渲染与自定义图标_renderArrow()返回!this._isDisabled() || this._isSorted()即已排序列即使被禁用也保留箭头。箭头使用投影插槽[matSortHeaderIcon]内置默认 SVG 图标可通过投影自定义th mat-sort-headername 名称 mat-icon matSortHeaderIconarrow_drop_down/mat-icon /th该插槽在 sort-header.html 中通过ng-content select[matSortHeaderIcon]声明。4.4 无障碍实现细节MatSortHeader在无障碍方面的设计是本节重点aria-sort 状态_getAriaSortAttribute()返回ascending | descending | none未排序时返回none使属性失效从而保证同一时刻只有一个表头携带有效aria-sort符合 ARIA 规范动作描述sortActionDescription默认Sort通过AriaDescriberangular/cdk/a11y以aria-describedby方式附加到按钮元素而非直接设置aria-label。源码注释解释了原因部分读屏器如 VoiceOver会同时朗读列头与按钮标签造成大量噪音sort-header.ts读屏反馈缺口官方文档 sort.md 明确指出多数读屏器不会播报aria-sort值变化因此建议监听matSortChange事件配合LiveAnnouncerangular/cdk/a11y向用户播报排序结果。五、全局默认配置MAT_SORT_DEFAULT_OPTIONSMAT_SORT_DEFAULT_OPTIONS是InjectionTokenMatSortDefaultOptions用于在模块级覆盖默认行为NgModule({ providers: [ { provide: MAT_SORT_DEFAULT_OPTIONS, useValue: {disableClear: true, arrowPosition: before} as MatSortDefaultOptions, }, ], })MatSort构造函数以Optional() Inject(MAT_SORT_DEFAULT_OPTIONS)注入该令牌sort.ts其disableClear参与方向循环的清除判定优先级最低MatSortHeader构造函数中若令牌携带arrowPosition会覆盖组件默认的aftersort-header.ts。MatSortDefaultOptions仅有arrowPosition?: SortHeaderArrowPosition与disableClear?: boolean两个可选字段SortHeaderArrowPosition为联合类型before | after。六、关键类型速查结合 sort-direction.ts 与 sort.tsSortDirection asc | desc | 空串表示“未排序/已清除”Sort { active: string; direction: SortDirection }matSortChange事件的载荷MatSortable { id: string; start: SortDirection; disableClear: boolean }表头向容器注册的接口。七、实战在 mat-table 中集成排序以下示例整合了本模块的核心用法参考 sort.md 与 sort.spec.ts 中验证过的行为// table-sorting.ts import {LiveAnnouncer} from angular/cdk/a11y; import {Component, ViewChild} from angular/core; import {MatSort, Sort} from angular/material/sort; interface Food { name: string; calories: number; } Component({ selector: table-sorting, template: table mat-table [dataSource]data matSort (matSortChange)announceSortChange($event) matSortStartdesc matSortDisableClearfalse ng-container matColumnDefname th mat-header-cell *matHeaderCellDef mat-sort-header sortActionDescription按名称排序名称/th td mat-cell *matCellDeflet item{{item.name}}/td /ng-container ng-container matColumnDefcalories th mat-header-cell *matHeaderCellDef mat-sort-header sortActionDescription按热量排序热量/th td mat-cell *matCellDeflet item{{item.calories}}/td /ng-container tr mat-header-row *matHeaderRowDefdisplayedColumns/tr tr mat-row *matRowDeflet row; columns: displayedColumns/tr /table , }) export class TableSortingComponent { data: Food[] [ {name: 牛肉, calories: 250}, {name: 豆腐, calories: 76}, ]; displayedColumns [name, calories]; ViewChild(MatSort) sort!: MatSort; constructor(private _liveAnnouncer: LiveAnnouncer) {} announceSortChange(sortState: Sort) { if (sortState.direction) { this._liveAnnouncer.announce(按 ${sortState.active} 排序方向 ${sortState.direction}); } else { this._liveAnnouncer.announce(排序已清除); } } }要点回顾表头只需写mat-sort-headerid 自动取自matColumnDefmatSortStartdesc将整个表格的起始方向反转为降序只对单列生效请改用表头的startmatSortDisableClearfalse保留“第三次点击清除排序”的默认行为设true可禁止清除在mat-table中使用时需在表头单元格内提供sortActionDescription并配合LiveAnnouncer播报matSortChange弥补读屏器不播报aria-sort变化的缺陷。八、常见错误与排查排序模块的错误信息集中在 sort-errors.ts均为开发模式下的主动校验便于快速定位问题错误触发条件MatSortHeader must be placed within a parent element with the MatSort directive.mat-sort-header缺少父级matSort容器ngOnInit中未注入到MatSort时抛出MatSortHeader must be provided with a unique id.注册的表头 id 为空Cannot have two MatSortables with the same id (${id}).同一容器下存在重复 id${direction} is not a valid sort direction (asc or desc).matSortDirection被赋值为非法方向九、测试验证行为即契约仓库中的 sort.spec.ts 与 testing 目录下的 TestHarness 共同保障了上述行为。其中 sort-harness.ts、sort-header-harness.ts 提供了面向组件的测试基础设施可配合MatSortHarness在单元测试中模拟点击表头、断言方向循环与事件载荷matSortChange、getNextSortDirection、arrowPosition、disableClear等关键行为均在测试中有对应覆盖。对于需要以组件测试方式验证排序逻辑的团队建议直接复用这套 Harness API而非编写面向 DOM 细节的脆弱断言。结语angular/material/sort通过“容器持有状态、表头触发变更”的清晰分工把表格排序从重复的样板代码中解放出来。理解其方向循环状态机[asc, desc, ]、MAT_SORT_DEFAULT_OPTIONS全局配置、sortActionDescription与LiveAnnouncer的无障碍组合是写出健壮、可访问、易维护的排序表格的关键。本文所有结论均可对照 goldens/material/sort/index.api.md 的公开契约与 src/material/sort 下的实现逐一验证。【免费下载链接】componentsComponent infrastructure and Material Design components for Angular项目地址: https://gitcode.com/GitHub_Trending/co/components创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考