ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Gutenberg 组件库 CustomSelectControlV2 实战指南:受控/非受控模式、多选与无障碍下拉选择

Gutenberg 组件库 CustomSelectControlV2 实战指南:受控/非受控模式、多选与无障碍下拉选择 Gutenberg 组件库 CustomSelectControlV2 实战指南受控/非受控模式、多选与无障碍下拉选择【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenbergCustomSelectControlV2是 Gutenberg 编辑器组件库wordpress/components中新一代的下拉选择控件构建在 Ariakit 之上用于渲染高度可定制的 select 组件。它在 WordPress 块编辑器及其周边界面中承担从一组选项中选取一个或多个值的表单交互支持非受控uncontrolled与受控controlled两种使用模式、多选multiple selection以及自定义选中值渲染renderSelectedValue。读完本文你将掌握该组件的完整 API、两种状态管理模式的正确写法、多选与无障碍键盘交互的实现细节以及其在仓库源码中的底层工作原理。说明本文内容以 packages/components/src/custom-select-control-v2/README.md 为骨架并结合该组件在仓库中的 入口实现、样式实现、Storybook 示例 与 浏览器端测试 进行纵深展开。一、组件概述两个子组件构成CustomSelectControlV2由两个独立组件组成CustomSelectControlV2外层包装组件与 Context Provider。它负责管理子组件CustomSelectControlV2.Item的状态所有选项的值、选中状态与事件回调都经由它统一协调。CustomSelectControlV2.Item渲染单个下拉选项。当defaultValue未定义时第一个CustomSelectControlV2.Item子元素会被用作默认选中值。从源码看两者的关系清晰体现在 index.tsx 的挂载语句CustomSelectControlV2.Item Item;中——Item作为静态属性挂载到主组件上因此使用方无需单独 import直接通过CustomSelectControlV2.Item组合使用即可这也是 Gutenberg 组件库常见的复合组件compound component模式。在 custom-select.tsx 中外层组件通过createContext创建了CustomSelectContext将store与size注入给所有子Item每个Item在渲染时通过useContext(CustomSelectContext)取回这些值见 item.tsx。这意味着选中态同步尺寸统一都由父级 store 驱动子项自身是无状态展示组件。二、开发指南三种典型用法1. 非受控模式Uncontrolled Mode在非受控模式下组件自己管理内部状态。可以通过defaultValue指定初始选中值若未设置该 prop则默认选中第一个子项。const UncontrolledCustomSelectControlV2 () ( CustomSelectControlV2 labelColors CustomSelectControlV2.Item valueBlue { /* The defaultValue since it wasnt defined */ } span style{ { color: blue } }Blue/span /CustomSelectControlV2.Item CustomSelectControlV2.Item valuePurple span style{ { color: purple } }Purple/span /CustomSelectControlV2.Item CustomSelectControlV2.Item valuePink span style{ { color: deeppink } }Pink/span /CustomSelectControlV2.Item /CustomSelectControlV2 );底层原理非受控模式的默认值逻辑由 index.tsx 中的Ariakit.useSelectStore({ defaultValue, value })驱动。当defaultValue为undefined时Ariakit 的 store 会自动以第一个非禁用non-disabled选项作为初始值——这与 README 与 types.ts 中的类型注释若留空undefined将使用第一个非禁用项完全吻合。组件本身不再维护额外 state选择逻辑全部委托给 store。2. 受控模式Controlled Mode受控模式下父组件通过value与onChange两个 prop 完全接管选中值的读写适合需要把选择结果同步到表单状态、Redux store 或区块属性block attributes的场景。const ControlledCustomSelectControlV2 () { const [ value, setValue ] useState string | string[] (); const renderControlledValue ( renderValue: string | string[] ) ( { /* Custom JSX to display renderValue item */ } / ); return ( CustomSelectControlV2 { ...props } onChange{ ( nextValue ) { setValue( nextValue ); props.onChange?.( nextValue ); } } value{ value } { [ blue, purple, pink ].map( ( option ) ( CustomSelectControlV2.Item key{ option } value{ option } { renderControlledValue( option ) } /CustomSelectControlV2.Item ) ) } /CustomSelectControlV2 ); };底层原理从 index.tsx 可以看到受控模式本质上是把value透传给 Ariakit store并通过setValue: ( nextValue ) onChange?.( nextValue )把 store 内部的每一次值变更回调到你的onChange。因此只要value由父组件持有选择结果就是完全可预测、可回放replay的。3. 多选模式Multiple Selection当value/defaultValue使用数组时多选功能即被启用onChange回调的参数类型也会随之变为string[]。const MultiSelectCustomSelectControlV2 () ( CustomSelectControlV2 defaultValue{ [ blue, pink ] } labelColors { [ blue, purple, pink ].map( ( item ) ( CustomSelectControlV2.Item key{ item } value{ item } { item } /CustomSelectControlV2.Item ) ) } /CustomSelectControlV2 );多选模式下触发按钮上的默认文案不再是单个值而是已选 N 项的计数文案。这一行为由 custom-select.tsx 中的defaultRenderSelectedValue实现空值显示Select an item选中 1 项显示该项本身选中多项则通过sprintf与_n输出本地化的%d item selected/%d items selected。选中的每一项前会显示对勾图标见下文Item渲染说明测试 index.browser.test.tsx 完整覆盖了多选的选中、追加与取消选中deselect流程。三、Props 全解析CustomSelectControlV2的 PropsProp类型必填默认值说明childrenReact.ReactNode是—子元素应由CustomSelectControlV2.Item组合而成defaultValuestring \| string[]否—非受控模式下的初始值若为undefined默认选中第一个非禁用项hideLabelFromVisionboolean否false视觉上隐藏 label但对屏幕阅读器始终可见labelstring是—控件的可访问标签accessible labelonChange( newValue: string \| string[] ) void否—值变化时回调接收新值renderSelectedValue( selectValue: string \| string[] ) React.ReactNode否—自定义选中值在触发按钮上的渲染方式用于展示富样式值sizedefault \| compact否default控件尺寸valuestring \| string[]否—受控模式下由外部控制的值CustomSelectControlV2.Item的 PropsProp类型必填说明valuestring是选项的值当children未定义时会直接用作显示文本childrenReact.ReactNode否每个选项要展示的内容未定义时回退使用value补充Item的disabled属性虽然在 README 的 Props 表格中未列出但 types.ts 中为Item额外定义了disabled?: boolean默认false。类型注释特别提醒禁用态需要自行添加样式例如降低透明度来从视觉上标识。在 styles.ts 中禁用项会获得cursor: not-allowed而选中态对勾与活动项高亮data-active-item样式同样在此文件中定义。四、源码级原理从 Props 到 DOM 的完整链路1. 入口Ariakit SelectStore 是状态核心入口文件 是整个组件的骨架function CustomSelectControlV2( props: WordPressComponentProps CustomSelectProps, button, false ) { const { defaultValue, onChange, value, ...restProps } props; // Forward props store from v2 implementation const store Ariakit.useSelectStore( { setValue: ( nextValue ) onChange?.( nextValue ), defaultValue, value, } ); return CustomSelect { ...restProps } store{ store } /; }可以看到组件是建立在 AriakituseSelectStore之上的薄封装所有选择状态、键盘导航、ARIA 属性都由 Ariakit 保证value、defaultValue、onChange被解构出来直接喂给 store其余 props 原样透传给内部CustomSelectWordPressComponentPropsCustomSelectProps, button, false表明最终渲染的语义元素是buttonARIA combobox 模式这与测试中getByRole(combobox)的断言一致。2. 渲染Label InputBase Popover 三层结构自定义渲染实现 展示了完整 DOM 结构Ariakit.SelectLabel渲染 label。当hideLabelFromVision为true时用VisuallyHidden包裹保证 label 仅对屏幕阅读器可见否则用BaseControl.VisualLabel正常渲染。测试 index.browser.test.tsx 专门验证了隐藏 label 后 combobox 仍能以 label 命名getByRole(combobox, { name })可命中。InputBase复用wordpress/components的输入基座组件suffix位置放入SelectControlChevronDown下箭头图标size透传。CustomSelectButton真正可点击的触发按钮通过Ariakit.useStoreState(store)实时读取当前值并按renderSelectedValue ?? defaultRenderSelectedValue决定按钮内展示内容见 custom-select.tsx。Styled.SelectPopover下拉浮层设置gutter{ 12 }与触发按钮的间距、sameWidth与按钮同宽、slide{ false }、flip{ ! isLegacy }浮层内部用CustomSelectContext.Provider向所有Item注入 store 与 size。3. Itemchildren 回退与选中对勾item.tsx 的渲染逻辑非常精简export function CustomSelectItem( { children, ...props }: WordPressComponentProps CustomSelectItemProps, div, false ) { const customSelectContext useContext( CustomSelectContext ); return ( Styled.SelectItem store{ customSelectContext?.store } size{ customSelectContext?.size ?? default } { ...props } { children ?? props.value } Styled.SelectedItemCheck Icon icon{ check } / /Styled.SelectedItemCheck /Styled.SelectItem ); }关键点children ?? props.value实现了children 未定义时回退显示 value的约定每个Item末尾固定渲染一个SelectedItemCheckcheck图标当前选中项会显示对勾该对勾的显示/隐藏由 styles.ts 控制——未选中项通过font-size: 0折叠占位选中项恢复24px字号显示图标displayName被显式设置为CustomSelectControlV2.Item便于 DevTools 调试与测试定位。4. 样式三种尺寸与动效styles.ts 定义了尺寸映射compact高度 32px、default高度 40px、small高度 24px并依据hasCustomRenderProp在minHeight与height之间切换自定义渲染时允许内容撑高。下拉浮层还内置了 slide-down fade-in 入场动画且遵循prefers-reduced-motion媒体查询在用户系统开启减少动态效果时自动关闭动画styles.ts这是 Gutenberg 组件库一贯的无障碍细节。五、无障碍与键盘交互测试实证该组件的浏览器端测试 index.browser.test.tsx 是最佳的行为契约文档以下行为均有测试断言背书标准 combobox 语义触发按钮 role 为combobox浮层 role 为listbox选项 role 为option多选时 listbox 带aria-multiselectable属性。键盘操作Tab聚焦 →Enter/ArrowDown打开浮层 →ArrowDown移动高亮 →Enter确认选择Escape关闭浮层且不改变当前选中值。字符输入筛选typeahead在聚焦状态下直接输入字符如a即可选中匹配的选项如amber即使浮层未打开也能生效。aria-selected同步切换选择后旧选项aria-selected变为false新选项变为true保证屏幕阅读器读到的选中状态始终正确。自定义渲染renderSelectedValue返回的图片只在选中项上渲染未选中选项的图片仅在下拉浮层打开时可见见 index.browser.test.tsx。这些能力全部来自底层 Ariakit 的 Select 组件——v2 不再像 v1 那样手工管理焦点与 ARIA而是声明式地交由经过无障碍审计的成熟库实现。六、使用状态与迁移建议仓库事实在 Storybook 元数据 中组件带有status-wip标签componentStatus.status为not-recommended其说明明确指出该组件将来会被wordpress/ui中的SelectControl取代在迁移完成之前官方建议继续使用 v1 的CustomSelectControl即packages/components/src/custom-select-control目录下的实现仓库中仍保留二者共存。因此如果你正在开发新的块编辑器扩展或自定义面板选择组件时应优先参考 Gutenberg 设计系统的当前推荐若你正在阅读或维护已有使用CustomSelectControlV2的代码本文的 API 与行为说明可以帮助你理解其实现并安全地迁移。七、延伸阅读组件官方文档README.md入口与状态管理index.tsx渲染与 Context 分发custom-select.tsx选项子组件item.tsxProps 类型定义types.ts样式与动效实现styles.ts可交互示例Storybook storiesstories/index.story.tsx行为契约测试test/index.browser.test.tsx同仓库的 v1 实现对比参考packages/components/src/custom-select-control/index.tsx如需在本地运行该组件的 Storybook 查看实际效果可在仓库根目录安装依赖后启动wordpress/components的 Storybook 工作流并在Components/Selection Input/Common/CustomSelectControl v2分类下查看 Default、MultipleSelection、CustomSelectedValue 三个示例。【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表