Angular Material Chips 组件完全指南:从静态展示到输入、选择与无障碍交互
Angular Material Chips 组件完全指南从静态展示到输入、选择与无障碍交互【免费下载链接】componentsComponent infrastructure and Material Design components for Angular项目地址: https://gitcode.com/GitHub_Trending/co/componentsChips纸片/标签是 Angular Material 中用于展示信息、执行选择、过滤内容和接收文本输入的核心 UI 组件。本文以 src/material/chips/chips.md 为骨架结合本仓库中angular/material/chips的源码实现与官方示例系统讲解mat-chip-set、mat-chip-listbox、mat-chip-grid三大容器及其对应 chip 元素的用法、键盘交互、表单集成、图标插槽、全局配置与无障碍实践帮助你根据业务场景选择正确的 Chips 交互模式并写出可无障碍访问的代码。Chips 的三种交互模式概览Chips 组件在本仓库中对应src/material/chips/目录所有组件、指令与相关类型统一通过MatChipsModule定义于 chips-module.ts导出包含MatChip、MatChipSet、MatChipListbox、MatChipOption、MatChipGrid、MatChipRow、MatChipInput、MatChipAvatar、MatChipEdit、MatChipRemove、MatChipTrailingIcon等 12 个声明。完整导出清单可查看 public-api.ts。Chips 支持 3 种用户交互模式每种模式都有独立的容器Container与 chip 元素交互模式容器单个元素无障碍模式典型场景Listbox选择mat-chip-listboxmat-chip-optionlistbox呈现一组可选选项单选或多选Text Entry文本输入mat-chip-gridmat-chip-rowgrid自由文本输入将输入内容转成 chipStatic Content静态展示mat-chip-setmat-chip视上下文而定展示不可交互的标签/信息列表静态 Chipsmat-chip-set 与 mat-chipChips 总是使用在一个容器内部。创建静态 chips 时先写一个mat-chip-set元素然后在其中嵌套mat-chip元素mat-chip-set mat-chip John /mat-chip mat-chip Paul /mat-chip mat-chip James /mat-chip /mat-chip-set默认情况下mat-chip会应用 Material Design 的样式对应基础组件MatChip定义于 chip.tsselector 为mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]。如果希望得到一个完全没有样式处理的 chip可以使用mat-basic-chip。注意Angular Material 并不打算让mat-chip、mat-basic-chip和mat-chip-set成为可交互元素。它们仅用于静态内容展示不应挂载点击、选择等交互行为。禁用外观Disabled appearance虽然mat-chip本身不可交互但你仍然可以通过设置disabled输入属性来呈现禁用外观mat-chip disabledOrange/mat-chip从源码看disabled会反映到宿主元素上chip.ts 的 host 绑定中通过[class.mdc-evolution-chip--disabled]: disabled和[class.mat-mdc-chip-disabled]: disabled同时应用 MDC 与 Material 两套禁用样式类。选择 Chipsmat-chip-listbox 与 mat-chip-option当需要从列表中单选或多选一项时使用mat-chip-listbox与mat-chip-option。创建方式先写mat-chip-listbox元素若允许用户选择多个选项则添加multiple属性随后为每个可用选项嵌套一个mat-chip-option元素mat-chip-listbox aria-labelselect a shirt size mat-chip-option Small /mat-chip-option mat-chip-option Medium /mat-chip-option mat-chip-option Large /mat-chip-option /mat-chip-listbox从 chip-listbox.ts 的实现来看MatChipListbox是MatChipSet的扩展它实现了ControlValueAccessor因此天然支持[(ngModel)]等表单绑定默认 role 为listbox并且会根据multiple值动态设置aria-multiselectable、根据选中状态暴露selectedgettermultiple时返回数组单选时返回单个MatChipOption。禁用的 mat-chip-option使用disabled输入属性可以禁用一个mat-chip-option。这会为其呈现禁用外观并阻止用户与其交互mat-chip-option disabledOrange/mat-chip-option键盘交互用户可以使用方向键arrow keys在 chips 之间移动焦点使用空格键space进行选中/取消选中。点击 chip 时也会使其获得焦点从而保证键盘导航从当前聚焦的 chip 开始。与输入框联动的 Chipsmat-chip-grid 与 mat-chip-row使用mat-chip-grid与mat-chip-row来辅助用户进行文本输入这是把用户输入的每一段文本转成一个 chip的经典标签录入场景。创建方式先写一个mat-chip-grid作为容器再添加一个input/元素并通过matChipInputFor输入属性把它注册到mat-chip-grid最后为每一条用户输入的数据嵌套一个mat-chip-row。一个完整可运行的最小示例对应官方示例 chips-input-example.html 与 chips-input-example.tsmat-form-field classexample-chip-list mat-labelFavorite Fruits/mat-label mat-chip-grid #chipGrid aria-labelEnter fruits for (fruit of fruits(); track fruit) { mat-chip-row (removed)remove(fruit) [editable]true (edited)edit(fruit, $event) [aria-description]press enter to edit fruit.name button matChipEdit [attr.aria-label]edit fruit.name mat-iconedit/mat-icon /button {{fruit.name}} button matChipRemove [attr.aria-label]remove fruit.name mat-iconcancel/mat-icon /button /mat-chip-row } /mat-chip-grid input placeholderNew fruit... [matChipInputFor]chipGrid [matChipInputSeparatorKeyCodes]separatorKeysCodes [matChipInputAddOnBlur]addOnBlur (matChipInputTokenEnd)add($event) / /mat-form-field对应的组件逻辑摘录自 chips-input-example.tsexport interface Fruit { name: string; } Component({ selector: chips-input-example, templateUrl: chips-input-example.html, styleUrl: chips-input-example.css, imports: [MatFormFieldModule, MatChipsModule, MatIconModule], }) export class ChipsInputExample { readonly addOnBlur true; readonly separatorKeysCodes [ENTER, COMMA] as const; readonly fruits signalFruit[]([{name: Lemon}, {name: Lime}, {name: Apple}]); readonly announcer inject(LiveAnnouncer); add(event: MatChipInputEvent): void { const value (event.value || ).trim(); if (value) { this.fruits.update(fruits [...fruits, {name: value}]); } event.chipInput!.clear(); } remove(fruit: Fruit): void { this.fruits.update(fruits { const index fruits.indexOf(fruit); if (index 0) { return fruits; } fruits.splice(index, 1); this.announcer.announce(Removed ${fruit.name}); return [...fruits]; }); } edit(fruit: Fruit, event: MatChipEditedEvent) { const value event.value.trim(); if (!value) { this.remove(fruit); return; } this.fruits.update(fruits { const index fruits.indexOf(fruit); if (index 0) { fruits[index].name value; return [...fruits]; } return fruits; }); } }输入注册机制matChipInputFor 与 matChipInputTokenEndmatChipInputFor指令MatChipInput定义于 chip-input.ts的作用是把input元素注册到mat-chip-grid其 setter 会调用this._chipGrid.registerInput(this)此后输入框的键盘、焦点、值变化事件都会同步给 chip grid。事件matChipInputTokenEndMatChipInputEvent在用户按下分隔键默认是 Enter或满足失焦添加addOnBlur条件时触发事件对象包含input原生input元素已弃用推荐使用chipInput.inputElementvalue输入框中的当前值字符串chipInput触发事件的MatChipInput指令实例可通过其clear()方法清空输入框。从源码 chip-input.ts 可以看到若干重要细节空输入 Backspace当输入框为空且用户按下 Backspace 时会聚焦到最后一个 chip_focusLastChip()并忽略按住不放造成的重复事件event.repeat检查避免误删多个 chip分隔键判定_isSeparatorKey支持纯数字 keyCode也支持带修饰键的SeparatorKey如{keyCode: ENTER, modifiers: [...]}并会校验修饰键组合避免在按 Ctrl/Cmd 组合键时误触发 chip 创建addOnBlurmatChipInputAddOnBlur默认false设为true后输入框失焦也会触发chipEnd事件separatorKeyCodesmatChipInputSeparatorKeyCodes默认继承MAT_CHIPS_DEFAULT_OPTIONS.separatorKeyCodes默认[ENTER]可传入 keyCode 数组或ReadonlySetmatChipInputDisabledInteractive若全局默认配置了inputDisabledInteractive禁用的输入框仍可保持可交互以 readonly 形式呈现host 绑定中会设置aria-disabledtrue与readonly属性。禁用 mat-chip-row同样使用disabled输入属性来禁用mat-chip-row为其呈现禁用外观并阻止用户交互mat-chip-row disabledOrange/mat-chip-row键盘交互与 listbox 一致用户可以通过方向键移动、空格键选中/取消。此外在mat-chip-grid场景中按Delete键可以删除移除当前 chip删除会触发该 chip 的removed输出事件因此只要需要删除功能就必须实现removed处理器示例中的remove(fruit)否则 UI 与数据会不同步。与 Autocomplete 组合mat-chip-grid可以与mat-autocomplete组合使用实现自由输入 下拉建议的增强体验官方示例见 chips-autocomplete-example.ts 与 chips-autocomplete-example.htmlform mat-form-field classexample-chip-list mat-labelFavorite Fruits/mat-label mat-chip-grid #chipGrid aria-labelFruit selection for (fruit of fruits(); track $index) { mat-chip-row (removed)remove(fruit) {{fruit}} button matChipRemove [attr.aria-label]remove fruit mat-iconcancel/mat-icon /button /mat-chip-row } /mat-chip-grid input namecurrentFruit placeholderNew Fruit... #fruitInput [(ngModel)]currentFruit [matChipInputFor]chipGrid [matAutocomplete]auto [matChipInputSeparatorKeyCodes]separatorKeysCodes (matChipInputTokenEnd)add($event) / mat-autocomplete #automatAutocomplete (optionSelected)selected($event); fruitInput.value for (fruit of filteredFruits(); track fruit) { mat-option [value]fruit{{fruit}}/mat-option } /mat-autocomplete /mat-form-field /form重要提示当MatChipsModule与MatAutocompleteModule一起使用时模块导入顺序很关键。为确保行为正确例如通过键盘选中 autocomplete 选项时不要再把输入的文本添加为 chip请务必在MatChipsModule之前导入MatAutocompleteModule。官方示例在组件imports数组中即为[MatFormFieldModule, MatAutocompleteModule, MatChipsModule, MatIconModule, FormsModule]的顺序见 chips-autocomplete-example.ts 的注释说明。与 Angular Forms 集成Chips 与angular/forms完全兼容支持FormField、FormsModule与ReactiveFormsModule三种方式MatChipListbox实现了ControlValueAccessorchip-listbox.ts 中提供MAT_CHIP_LISTBOX_CONTROL_VALUE_ACCESSOR支持[(ngModel)]、formControlName等模板驱动与响应式表单绑定MatChipGrid同时实现了ControlValueAccessor与MatFormFieldControlchip-grid.ts因此可以直接作为MatFormField的控件使用获得校验状态errorState、aria-invalid、required与占位符等表单字段能力。三种表单风格的完整示例分别位于仓库基于 signal 的模板表单chips-signal-form传统模板驱动表单chips-template-form响应式表单chips-reactive-form。图标与删除按钮Avatar、Trailing Icon 与 matChipRemove可以为 chip 添加图标来标识实体如人物头像或提供额外功能。所有 chip 变体mat-chip、mat-chip-option、mat-chip-row都支持通过内容投影content projection添加图标。前槽位Front Slot头像一个 chip 有两个图标槽位。前槽位用于放置头像图片只需在mat-chip内部嵌套一个带有matChipAvatar属性的元素mat-chip mat-chip-avatar img src... / /mat-chip-avatar User name /mat-chip从源码 chip-icons.ts 看MatChipAvatar指令selector 为mat-chip-avatar, [matChipAvatar]会应用mdc-evolution-chip__icon--primary样式类并设置roleimg使头像对无障碍技术可见。后槽位Back SlotmatChipTrailingIcon 与 matChipRemove后槽位用于放置额外的图标在 chip 内嵌套带matChipTrailingIcon或matChipRemove属性的元素即可。其中MatChipTrailingIcon是非交互的尾随图标源码中设置了aria-hiddentrue而matChipRemove则是可交互的删除按钮。删除按钮Remove Button有时用户需要删除某个 chip可通过matChipRemove提供该能力。matChipRemove渲染在 chip 的后槽位点击时会触发 chip 的removed输出事件。创建方式是在mat-chip-option内部嵌套一个带matChipRemove属性的button元素mat-chip-option Orange button matChipRemove aria-labelRemove orange mat-iconcancel/mat-icon /button /mat-chip-option务必实现removed输出事件否则数据无法同步删除。源码层面MatChipRemovechip-icons.ts内部_handleClick会调用this._parentChip.remove()_handleKeydown则会在 Enter 或空格键按下时同样触发remove()即键盘用户按 Enter 也能删除 chip。无障碍最佳实践请参见下文无障碍章节。编辑能力matChipEdit作为输入型 chip 的补充MatChipRow支持editable输入属性与edited输出事件见 chip-row.ts配合matChipEdit指令定义于 chip-icons.ts点击或按 Enter 触发_parentChip._edit(event)即可实现点击编辑 chip 文本的能力示例中edit(fruit, $event)处理器会接收MatChipEditedEvent含value字段并更新数据。方向堆叠展示默认情况下chips 水平排列。要让 chips 垂直堆叠可给mat-chip-set、mat-chip-listbox或mat-chip-grid应用mat-mdc-chip-set-stacked类mat-chip-set classmat-mdc-chip-set-stacked mat-chipItem 1/mat-chip mat-chipItem 2/mat-chip /mat-chip-set全局配置默认值MAT_CHIPS_DEFAULT_OPTIONS使用MAT_CHIPS_DEFAULT_OPTIONS令牌可以为整个 chips 模块指定默认选项。该令牌定义于 tokens.ts接口MatChipsDefaultOptions支持以下字段配置项类型默认值说明separatorKeyCodesreadonly (number \| SeparatorKey)[] \| ReadonlySetnumber \| SeparatorKey[ENTER]触发chipEndmatChipInputTokenEnd事件的分隔键码列表hideSingleSelectionIndicatorbooleanfalse是否在单选模式下隐藏选中指示图标inputDisabledInteractivebooleanfalse禁用的 chip 输入框是否默认保持可交互注意SeparatorKey类型的键码还可以附带修饰键modifiers用于精确控制哪些组合键才算分隔键。在 standalone 模式下通过bootstrapApplication的 providers 全局覆盖import {COMMA, SPACE} from angular/cdk/keycodes; import {MAT_CHIPS_DEFAULT_OPTIONS} from angular/material/chips; bootstrapApplication(MyApp, { providers: [ { provide: MAT_CHIPS_DEFAULT_OPTIONS, useValue: { separatorKeyCodes: [COMMA, SPACE] } } ] });在基于 NgModule 的架构中则通常在AppModule的providers中提供该令牌。底层实现上chips-module.ts 在模块级以useValue: {separatorKeyCodes: [ENTER]}提供默认值而 tokens.ts 中令牌本身声明为providedIn: root并带有相同默认值的工厂函数MatChipInput在构造时会inject(MAT_CHIPS_DEFAULT_OPTIONS)读取该配置作为separatorKeyCodes与disabledInteractive的初始值chip-input.ts因此全局配置对每个 chip 输入框均生效。三种交互模式的完整示例Listbox选择衬衫尺码mat-chip-listbox aria-labelselect a shirt size mat-chip-option Small /mat-chip-option mat-chip-option Medium /mat-chip-option mat-chip-option Large /mat-chip-option /mat-chip-listboxmat-chip-listbox与mat-chip-option实现 listbox 无障碍模式用于呈现一组用户可选择的选项。Text Entry三明治配料输入mat-chip-grid与mat-chip-row实现 grid 无障碍模式用作自由文本输入的一部分允许用户输入文本以添加 chipsmat-form-field mat-chip-grid #myChipGrid [(ngModel)]mySelection aria-labelenter sandwich fillings for (filling of fillings; track filling) { mat-chip-row (removed)remove(filling) {{filling.name}} button matChipRemove mat-iconcancel/mat-icon /button /mat-chip-row } /mat-chip-grid input [matChipInputFor]myChipGrid [matChipInputSeparatorKeyCodes]separatorKeysCodes (matChipInputTokenEnd)add($event) aria-labelAdd sandwich fillings... / /mat-form-field无障碍提示请确保input元素是mat-chip-grid的兄弟节点sibling以保证 Voice Control 等无障碍设备能正确访问输入元素同时建议为输入框设置合适的aria-label以优化其可访问性。Static Content配料列表mat-chip-set与mat-chip可以模拟ul/li语义将一组不可交互的条目以列表形式呈现。做法是给mat-chip-set设置rolelist给每个mat-chip设置rolelistitemmat-chip-set rolelist mat-chip rolelistitem Sugar /mat-chip mat-chip rolelistitem Spice /mat-chip mat-chip rolelistitem Everything Nice /mat-chip /mat-chip-set而不加 role 的mat-chip-set/mat-chip组合不实现任何特定无障碍模式请根据具体上下文自行补充合适的无障碍属性如aria-label。无障碍最佳实践以下是使用 Chips 时的无障碍Accessibility要点汇总按场景选择变体上文三种交互模式描述的三种变体各有其无障碍语义请选择最贴合你业务场景的变体——需要选择用 listbox需要文本输入用 grid纯展示用静态 chip。容器必须有无障碍标签对MatChipGrid和MatChipListbox务必通过aria-label或aria-labelledby为控件提供可访问的标签示例中的aria-labelEnter fruits、aria-labelselect a shirt size等。matChipRemove 必须用于 button 元素始终把matChipRemove应用在button元素上永远不要直接应用在mat-icon元素上。同时为按钮补充aria-label如示例中的aria-labelRemove orange否则屏幕阅读器无法获知按钮用途。不要在 mat-chip-option 中嵌套交互控件使用MatChipListbox时切勿在mat-chip-option内部嵌套其他交互控件按钮、链接等。嵌套控件会显著降低辅助技术用户的体验。不要隐藏单选指示器默认情况下MatChipListbox会显示一个对勾checkmark来标识选中项。虽然可以通过hideSingleSelectionIndicator在单选模式下隐藏该指示器但这会降低组件的可访问性——用户将更难甚至无法通过视觉识别选中项建议保持默认显示。为可编辑 chip 提供键盘说明当 chip 可编辑[editable]true时需要向辅助技术说明如何用键盘编辑该 chip。一种做法是添加aria-description属性写明按回车键编辑该 chip之类的指引官方示例中即使用了[aria-description]press enter to edit fruit.name。进阶阅读组件源码与单元测试src/material/chips/目录下的 chip.ts、chip-option.ts、chip-row.ts、chip-set.ts、chip-listbox.ts、chip-grid.ts 及各自的.spec.ts测试文件官方可运行示例仓库src/components-examples/material/chips/下的 chips-overview、chips-input、chips-autocomplete、chips-avatar、chips-stacked、chips-form-field、chips-drag-drop 等组件测试 Harnesssrc/material/chips/testing/目录提供了ChipHarness、ChipOptionHarness、ChipListboxHarness、ChipInputHarness、ChipGridHarness、ChipRemoveHarness等测试工具类可用于编写组件级测试。【免费下载链接】componentsComponent infrastructure and Material Design components for Angular项目地址: https://gitcode.com/GitHub_Trending/co/components创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考