
Angular aria 组件库 Accordion 公共 API 深度解析angular/aria_accordion 信号式指令全指南【免费下载链接】componentsComponent infrastructure and Material Design components for Angular项目地址: https://gitcode.com/GitHub_Trending/co/components本篇文章以angular/aria_accordion的官方 API 报告API Extractor 生成的 golden 文件为骨架系统讲解ngAccordionGroup、ngAccordionTrigger、ngAccordionPanel、ngAccordionContent四个公共指令与ACCORDION_GROUP注入令牌的完整公共 API并结合本仓库源码src/aria/accordion深入其信号式输入、ARIA 无障碍处理、键盘导航模式、懒渲染与开发模式校验机制。读完本文你将掌握这套无样式 WAI-ARIA Accordion 模式的信号式 API 全貌能够独立搭建、配置、测试并无障碍化一个 Angular 手风琴组件。1. API 报告是什么golden 文件的价值与约束本仓库将angular/aria_accordion的公共 API 面以 API Report 形式固化在 goldens/aria/accordion/index.api.md 中。该文件由 API Extractor 自动生成文件头部明确标注Do not edit this file. It is a report generated by API Extractor.它记录了该包对外暴露的全部可导出符号及其精确签名是判断哪些成员属于公共 API、哪些是内部实现的唯一权威依据。任何对公共 API 的破坏性修改例如删除AccordionGroup.expandAll()都会在 golden 校验阶段被拦截。从报告可见该包仅依赖 Angular 核心angular/core与 CDK 的 bidi 模块angular/cdk/bidi无任何样式依赖是一个纯逻辑、无样式unstyled的 ARIA 模式实现。2. 公共 API 总览报告显示angular/aria_accordion共导出4 个公共指令类 1 个注入令牌全部标记为public符号选择器导出名职责AccordionGroup[ngAccordionGroup]ngAccordionGroup手风琴容器管理展开模式、禁用与键盘导航AccordionTrigger[ngAccordionTrigger]ngAccordionTrigger触发按钮控制关联面板的展开/折叠AccordionPanel[ngAccordionPanel]ngAccordionPanel内容面板容器条件渲染并负责无障碍隐藏AccordionContentng-template[ngAccordionContent]—结构性指令实现面板内容的懒渲染ACCORDION_GROUP——InjectionTokenAccordionGroup暴露组实例这些导出与 public-api.ts 完全一致该文件还额外以ɵɵ前缀内部重导出了DeferredContent/DeferredContentAware用于解决 angular/components#30663 所述的链接问题但这两个符号不属于公共 API不会出现在 golden 报告中。报告同时印证了这套 API 是信号Signal优先的现代 Angular 实现大量输入使用InputSignalWithTransformboolean, unknown布尔属性变换、ModelSignalboolean双向绑定、WritableSignalDirection、Signalboolean计算状态等类型。3. 最小可用示例三个指令如何协作AccordionGroup的源码注释accordion-group.ts给出了完整的组合用法。一个典型的手风琴由三层结构组成div ngAccordionGroup [multiExpandable]true div classaccordion-item h3 button ngAccordionTrigger [panel]panel1Item 1/button /h3 div ngAccordionPanel #panel1ngAccordionPanel ng-template ngAccordionContent pContent for Item 1./p /ng-template /div /div div classaccordion-item h3 button ngAccordionTrigger [panel]panel2Item 2/button /h3 div ngAccordionPanel #panel2ngAccordionPanel ng-template ngAccordionContent pContent for Item 2./p /ng-template /div /div /div关键协作链路对应 accordion-trigger.ts 的ngOnInitngAccordionTrigger通过必填输入panel拿到它控制的面板模板引用#panel1ngAccordionPanel触发器的ngOnInit创建AccordionTriggerPattern并回调panel()._pattern this._pattern将自身 pattern 挂到面板上触发器将自己注册进AccordionGroup内部维护的SortedCollectionAccordionTriggeraccordion-group.ts由组统一协调导航与展开状态。面板内容必须包在ng-template[ngAccordionContent]中——若缺少该内容开发模式会在控制台报告违规详见第 8 节。4. AccordionGroup组的全局状态与行为AccordionGroupaccordion-group.ts是整组手风琴的根声明选择器[ngAccordionGroup]并通过providers: [{provide: ACCORDION_GROUP, useExisting: AccordionGroup}]向子树暴露自己。4.1 四个布尔输入InputSignalWithTransform所有输入均通过booleanAttribute变换因此支持[disabled]expr与disabled两种写法全部有默认值输入默认值语义disabledfalse是否禁用整组。禁用后所有触发器同时进入禁用态见第 6 节的disabled计算逻辑multiExpandabletrue是否允许多个面板同时展开。设为false时展开新项会自动折叠其他项单展开模式softDisabledtrue软禁用为true时被禁用的项仍可获得焦点focusable但不可交互为false时禁用项在键盘导航中被直接跳过硬禁用wrapfalse键盘导航是否在第一项与最后一项之间循环回绕其中multiExpandable的默认值为true与 Material 风格手风琴默认单展开的直觉不同使用时需注意如果不显式设置同一时刻可以展开任意多个面板。4.2 公开方法expandAll(): void // 展开所有面板仅当 multiExpandable 时有效 collapseAll(): void // 折叠所有面板二者内部直接委托给 pattern 的expansionBehavior.openAll()/closeAll()src/aria/private/accordion/accordion.ts即ListExpansion行为。4.3 只读公开成员element: HTMLElement宿主 DOM 元素引用来自注入的ElementReftextDirection: WritableSignalDirection文档/容器的文字方向ltr/rtl注入自 CDK 的Directionality.valueSignal供键盘导航方向计算使用_collection、_pattern内部实现_前缀表示非公共 API_pattern即AccordionGroupPattern。4.4 宿主事件委托宿主上绑定了三个事件并委托给 patternaccordion-group.ts(keydown) → _pattern.onKeydown($event) (click) → _pattern.onClick($event) (focusin) → _pattern.onFocus($event)事件在组层面统一捕获再由 pattern 依据事件目标查找对应的触发器 pattern_findTriggerPattern会向上冒泡查找最近的[ngAccordionTrigger]实现事件委托 单个监听器的高效模式。5. AccordionTrigger唯一交互入口AccordionTriggeraccordion-trigger.ts是用户点击/键盘操作的唯一入口选择器[ngAccordionTrigger]导出名ngAccordionTrigger。5.1 输入与双向绑定成员类型说明panelInputSignalAccordionPanel必填本触发器控制的面板模板引用未传入将无法工作idInputSignalstring触发器 id默认由 CDK_IdGenerator自动生成前缀ng-accordion-trigger-disabledInputSignalWithTransformboolean, unknown默认false单触发器级禁用与组的disabled取并集expandedModelSignalboolean默认false可双向绑定的展开状态[(expanded)]读写展开/折叠时触发expandedChange输出expanded采用ModelSignal这是 golden 报告中唯一出现的输出事件{ expanded: expandedChange }意味着你可以用 Angular 标准的[(expanded)]...语法与外部状态同步。5.2 只读计算信号panelId: Signalstring关联面板的 idcomputed(() this.panel().id())用于生成aria-controlsactive: Signalboolean当前是否为组内活动项roving tabindex 焦点项。5.3 公开方法expand(): void collapse(): void toggle(): void三个方法分别代理到 pattern 的open()/close()/toggle()最终由组内的ListExpansion行为执行保证与键盘、点击行为走同一套展开逻辑。5.4 无障碍宿主属性触发器自动输出完整的 ARIA 状态accordion-trigger.tsrolebutton // 静态角色 [id] // 自动生成或自定义 [attr.aria-expanded] // expanded() [attr.aria-controls] // 指向面板 idpanelId [attr.aria-disabled] // disabled() [attr.disabled] // 仅硬禁用时输出 [attr.tabindex] // 焦点项为 0其余为 -1 [attr.data-active] // 活动项标记测试与样式钩子此外构造函数有一个细节若宿主是button且未显式写type会自动补typebutton防止触发表单提交accordion-trigger.ts。6. AccordionPanel条件可见的内容容器AccordionPanelaccordion-panel.ts是内容面板选择器[ngAccordionPanel]导出名ngAccordionPanel。6.1 输入与宿主指令id: InputSignalstring面板 id默认自动生成前缀ng-accordion-panel-通过hostDirectives: [{directive: DeferredContentAware, inputs: [preserveContent]}]继承preserveContent输入为true时面板内容在首次渲染后保留在 DOM 中仅切换可见性为false默认时折叠后面板内容会从 DOM 中移除。6.2 可见性状态readonly visible computed(() this._pattern?.expanded() true);面板的可见性完全由控制它的触发器的展开状态决定_pattern由触发器在ngOnInit时注入见第 3 节。同时afterRenderEffect会把visible同步到DeferredContentAware.contentVisible驱动懒渲染。6.3 无障碍宿主属性roleregion // 静态区域角色 [attr.id] // 面板 id [attr.aria-labelledby] // 指向触发器 id_pattern?.id() [attr.inert] // 不可见时置 true可见时移除inert属性的使用是这套实现的可访问性亮点面板折叠时不仅视觉隐藏还通过inert将其内容整体移出 Tab 键序与辅助技术屏幕阅读器的感知范围而不是仅仅依赖aria-hiddenaccordion-panel.ts。6.4 公开方法expand(): void // 展开本项 collapse(): void // 折叠本项 toggle(): void // 切换本项均代理到_pattern的open()/close()/toggle()。7. AccordionContent懒渲染的结构性指令AccordionContentaccordion-content.ts是最简单的一个公共指令——本身没有任何逻辑只是Directive({ selector: ng-template[ngAccordionContent], hostDirectives: [DeferredContent], }) export class AccordionContent {}它必须作用于ngAccordionPanel内部的ng-template上通过宿主指令DeferredContent实现懒渲染面板内容只有在首次展开时才被创建进 DOM从而减少初始渲染成本。与preserveContent组合即可精确控制内容何时创建、何时销毁。8. 键盘导航与焦点管理源码级原理所有交互逻辑沉淀在AccordionGroupPattern/AccordionTriggerPatternsrc/aria/private/accordion/accordion.ts它们组合了三个可复用行为ListNavigation导航、ListFocus焦点、ListExpansion展开。8.1 按键映射keydown计算信号accordion.ts定义了完整键盘契约按键行为ArrowUp移动到上一触发器ArrowDown移动到下一触发器Home跳转到第一项End跳转到最后一项Space/Enter切换当前活动项的展开状态方向键依据orientation()决定手风琴固定为纵向orientation: () vertical因此 prev/next 恒为ArrowUp/ArrowDowntextDirection的 rtl 分支是为横向列表预留的通用逻辑。8.2 Roving Tabindex 与禁用态焦点模式固定为rovingaccordion.ts组内同一时刻只有一个触发器tabindex0其余为-1tabIndexcomputed见第 5.4 节onFocus仅在目标可聚焦focusBehavior.isFocusable时更新活动项避免点击禁用项导致焦点漂移两级禁用语义清晰accordion.tsdisabled trigger.disabled || group.disabled任一来源禁用即禁用hardDisabled disabled !group.softDisabled软禁用时仍可聚焦tabindex0但不可展开硬禁用时导航直接跳过。wrap为true时ListNavigation在首尾项之间循环false时到达边界即停止。8.3 点击行为click管理器在事件目标上查找对应触发器后依次执行navigationBehavior.goto(item)同步焦点与expansionBehavior.toggle(item)切换展开保证点击与键盘的操作路径完全一致。9. 开发模式校验不变量守卫当ngDevMode开启时开发构建默认开启各指令通过afterRenderEffect调用reportViolations在控制台输出可操作错误。已知校验项包括面板缺少内容accordion-panel.tsngAccordionPanel must have an ngAccordionContent to render.面板没有触发器accordion-panel.tsngAccordionPanel must have an ngAccordionTrigger to control it.触发器嵌套在自身面板内accordion-trigger.ts触发器不得嵌套在其控制的面板内部否则折叠后将不可达。面板被多个触发器控制accordion-trigger.tsngAccordionPanel is already controlled by another ngAccordionTrigger.单展开模式下初始多开accordion.tsmultiExpandablefalse但初始就展开了多个面板时报告违规。这些校验全部在开发模式运行、生产构建自动剥离零运行时成本。10. 测试与 Component Harness10.1 单元测试accordion.spec.ts775 行是验证 API 契约的权威测试套件覆盖ARIA 属性触发器有rolebutton、默认补typebutton、折叠时aria-expandedfalse、aria-controls精确指向面板 id、禁用时aria-disabledtrue使用provideFakeDirectionality(ltr)模拟文字方向并在每个用例后执行runAccessibilityChecks做自动化 a11y 回归通过派发真实PointerEvent/KeyboardEvent验证点击与方向键ArrowDown/ArrowUp/Home/End/Space/Enter行为。10.2 Component Harness测试环境驱动请使用 testing/accordion-harness.ts 提供的AccordionHarnesshostSelector为[ngAccordionTrigger]查询面板内容时会依据aria-controls自动解析到对应[ngAccordionPanel][id...]子树getRootHarnessLoader覆写过滤条件with({title, expanded, disabled})支持按标题、展开态、禁用态筛选APItoggle()/expand()/collapse()/isExpanded()/isDisabled()/getTitle()配合AccordionSection.TRIGGER | PANEL枚举定位内容区。11. 源码地图按图索骥关注点位置公共 API 声明golden 报告goldens/aria/accordion/index.api.md公共导出入口src/aria/accordion/public-api.ts组指令src/aria/accordion/accordion-group.ts触发器指令src/aria/accordion/accordion-trigger.ts面板指令src/aria/accordion/accordion-panel.ts懒渲染指令src/aria/accordion/accordion-content.ts注入令牌src/aria/accordion/accordion-tokens.ts交互/导航/展开核心src/aria/private/accordion/accordion.ts单元测试src/aria/accordion/accordion.spec.tsComponent Harnesssrc/aria/accordion/testing/accordion-harness.ts12. 总结与使用建议angular/aria_accordion是一套无样式、信号驱动、无障碍完备的 WAI-ARIA Accordion 模式实现其公共 API 全部固化在 golden 报告中天然具备接口稳定性保障。实际使用时的几条关键结论默认是多展开模式multiExpandable默认true需要经典单展开手风琴务必显式设置[multiExpandable]false触发器与面板通过必填输入[panel]和模板引用#panelngAccordionPanel关联缺少任一方都会被开发模式校验拦截面板内容必须包裹在ng-template[ngAccordionContent]中才能获得懒渲染与inert无障碍隐藏展开状态通过[(expanded)]双向绑定即可与组件外部状态同步面板的inert折叠隐藏与触发器的 roving tabindex 提供了符合 WCAG 标准的键盘与辅助技术体验无需自行编写任何 ARIA 代码。【免费下载链接】componentsComponent infrastructure and Material Design components for Angular项目地址: https://gitcode.com/GitHub_Trending/co/components创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考