ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

React Spectrum API 设计规范:构建统一组件 API 的命名与结构设计准则

React Spectrum API 设计规范:构建统一组件 API 的命名与结构设计准则 React Spectrum API 设计规范构建统一组件 API 的命名与结构设计准则【免费下载链接】react-spectrumA collection of libraries and tools that help you build adaptive, accessible, and robust user experiences.项目地址: https://gitcode.com/GitHub_Trending/re/react-spectrumspecs/api/Guidelines.md是 React Spectrum 仓库中为 v3 架构制定的一套组件 API 设计规范它规定了从布尔属性命名、事件回调、受控/非受控组件到组件拆分、DOM 属性透传在内的全部 API 设计决策准则。本文完整继承该规范的每一条规则并结合仓库中 Shared.md共享 API 基线、Button 包入口 与 RangeSlider 等真实源码逐一印证规则的落地方式帮助你在阅读 React Spectrum / react-aria 源码或为自己的组件库设计 API 时获得一套可对照、可执行的设计方法论。规范定位为什么需要统一的 API 设计准则React Spectrum 采用三层架构react-types类型层、react-stately状态层、react-aria/react-spectrum呈现层参见 2019-v3-architecture.md。在这样分层的体系中数百个组件的 API 如果各自为政使用者的心智成本将急剧上升。因此仓库在 specs/api/ 目录下沉淀了一批 API 规格文档如 Button.md、TextFields.md而 specs/api/Guidelines.md 则是所有组件规格文档共同遵守的“元规范”。规范中还定义了跨组件复用的共享 API 基线收录在 Shared.md 中例如输入类组件的InputBase、值类组件的ValueBase、选择类组件的SelectionOptions以及拖放基线DndBase。理解这些基线是理解各条命名规则的前提。布尔属性Boolean Props命名规范对布尔属性给出了四类前缀约定分别对应四种语义表示组件状态的布尔属性以is开头。例如isDisabled、isRequired。表示对用户可执行操作的限制的布尔属性以allows开头。例如allowsSelection、allowsDuplicates。控制某个选项显示或隐藏的布尔属性根据默认值选择show或hide开头默认可见则用hideXxx表示可以关掉默认隐藏则用showXxx表示可以打开。控制组件行为的布尔属性以should开头。例如shouldFlip、shouldCache。其余关键规则大多数布尔属性的默认值应为false。用户的典型操作是“打开某个选项”而不是“关闭一个默认开启的选项”。永远不要用render开头命名布尔属性如renderIcon因为它会与 render prop 函数混淆——后者才是真正“渲染该内容”的回调。应改用showIcon。可能合理支持超过两个取值的属性不要用布尔类型即使当前只支持两种状态。例如用validationStateinvalid而不是isInvalid这样未来可以支持validationStatevalid。仓库源码印证了这套约定Shared.md 中InputBase接口将isDisabled、isRequired、isReadOnly统一为is前缀的状态属性而validationState?: valid | invalid正是“为多值扩展预留空间”规则的体现该属性在 datepicker/Input.tsx、datepicker/DateField.tsx 等输入类组件中实际使用。同时SelectionOptions中的allowsSelection、allowsMultipleSelection、allowsEmptySelection演示了allows前缀的用法。事件回调Event Callback Props命名规范对事件回调的命名要求事件回调以on开头例如onSelect。如果需要向回调传递值值作为第一个参数。如果存在事件对象作为最后一个参数传入。尽可能使用平台无关的事件命名。例如用onPress而不是onClick以便支持移动/触摸设备而不仅是鼠标事件。如果事件是某个传入 prop 的变更事件事件名以Change结尾例如onSelectionChange。onChange只用于对应valueprop其他变更事件应在on和Change之间加入相关名词例如onSelectionChange。事件名使用现在时态例如onChange而不是onChanged。仓库中可以找到onPress这类平台无关事件的大量使用实例如 dialog/Dialog.tsx、tag/TagGroup.tsx、table/TableViewBase.tsx 等文件均通过onPress承接按压语义而非点击语义。onChange与value的对应关系则直接体现在共享基线中——Shared.md 的ValueBaseT接口将value、defaultValue与onChange?: (value: T, e?: Event) void三者捆绑在一起正是“值在第一、事件对象在最后”的签名规范。Children 与 Props 的取舍规范建议组件的主内容应使用children而非字符串 prop。这允许用户放入任意自定义格式如 JSX而不是被强制只支持纯文本。内容列表也尽量用children例如MenuItemchildren 而不是一个 options 数组。这样用户可以同时自定义每一项的内容和项本身。子组件的命名以主组件名开头例如Menu包含MenuItemchildren。对于接受多块内容、children会产生歧义的组件主内容取 children其余作为 props。例如AccordionItem除了children外还有一个titleprop。Render Props规范对 render prop 的使用给出四条规则当部分渲染职责需要委托给用户时才使用 render prop。render prop 以render开头命名例如renderItem、renderDragView。将待渲染的项作为参数传给 render prop。一般情况下应优先使用 children但在 children 无法覆盖的场景使用 render prop例如虚拟化列表就需要renderItemprop因为列表项按需生成无法预先以 children 形式声明。Shared.md 中的DragDelegate.renderDragView(items: any[]) ReactNode即是一个符合“参数传入待渲染项”规则的 render 型回调。受控与非受控组件规范规定对于用户可以修改的 prop应同时支持受控值。非受控版本的命名以default开头其余部分与受控 prop 同名。例如存在受控的valueprop 时非受控版本就是defaultValue。Shared.md 的ValueBaseT将该模式固化为value?defaultValue?onChange?的三件套。在 slider/RangeSlider.tsx 中可以看到这个约定在实现层的拆解方式let {onChange, onChangeEnd, value, defaultValue, getValueLabel, ...otherProps} props; // ... value: value ! null ? [value.start, value.end] : undefined,value与defaultValue从 props 中显式取出并转换后交给底层状态逻辑其余 props 透传——这正是“受控/非受控双支持”在组件内部的标准落地形态。方向无关命名Direction Agnostic Naming为了支持 RTL从右到左书写方向规范明确永远不要用left或right作为对齐或定位的命名改用start或end——它们会随书写方向自动映射到左或右从而让 UI 在 RTL 模式下自动翻转。唯一例外当确实需要让用户指定绝对的左或右、而不是基于书写方向时才可以使用left/right。这一规则在仓库源码中体现得非常直接Shared.md 定义了RangeValueT { start: T, end: T }与Alignment start | end类型RangeSlider 在处理区间值时正是以value.start/value.end访问两端而非left/right。基于索引的 Prop 与基于值的 Prop尽可能避免基于索引的 prop例如selectedIndex优先使用基于值的 prop例如selectedItem。索引会在条目增删时失效而值保持一致。如果要通过值引用一个子元素子元素应支持valueprop。例如MenuItem有valueprop使Select和ComboBox能按值引用它。这与 Shared.md 中SingleSelectionBase/MultipleSelectionBase以selectedItem/selectedItems值数组而非索引作为受控属性的设计一致。组件拆分Splitting Components规范给出了两个拆分的判断标准当选项组合不再合理时拆分为独立组件。例如Button和ActionButton的选项不同就应当是独立组件。当 prop 的类型发生变化时拆分组件。例如Slider与RangeSlider接受不同的valueprop——前者是单值后者是区间。仓库中的 Button 包 正是这条规则的完整例证它从一个包中导出了语义各异的按钮族export {Button} from adobe/react-spectrum/Button; export {ActionButton} from adobe/react-spectrum/ActionButton; export {FieldButton} from adobe/react-spectrum/private/button/FieldButton; export {LogicButton} from adobe/react-spectrum/LogicButton; export {ClearButton} from adobe/react-spectrum/private/button/ClearButton; export {ToggleButton} from adobe/react-spectrum/ToggleButton;Slider单值与RangeSlider区间值RangeSlider.tsx并存于同一目录而保持独立组件同样遵循“值类型不同则拆分”的原则。属性约束命名Prop Restrictions约束其他 prop 的 prop应在名称末尾带上主 prop 的名字。例如minValue约束的是value如果只叫min会产生歧义——到底约束的是哪个属性Shared.md 的RangeInputBaseT接口将该规则落实为minValue?、maxValue?另附step?与ValueBaseT的value形成明确的约束关系。DOM 属性透传DOM Props规范对 DOM 属性的透传提出三条要求所有合法的 DOM prop 都应始终透传到组件根 HTML 元素。DOM prop 应与组件的默认计算出的 DOM prop 合并。例如用户的className应与默认 Spectrum CSS 类名合并而不是覆盖。事件应与默认实现链式调用。例如用户的onKeyDown应在组件内部的键盘处理逻辑之外被执行而不是替代它。这三条保证了组件在“可定制性”与“内置行为完整性”之间取得平衡用户覆写样式不破坏组件结构用户提供事件处理不破坏无障碍与键盘交互逻辑。子元素定制Child Element Customization当一个组件由多个子元素组合而成时例如SplitButton组合了两个按钮和一个Menu规范要求支持childElementPropsprop以便用户对这些内部子元素做定制如自定义 CSS 类、测试用的 prop 或其他 DOM propchildElementProps是一个从子元素名到 DOM prop 对象的映射。例如SplitButton的菜单触发按钮可通过childElementProps.trigger定制。只应支持这些元素的合法 DOM prop不应支持可能覆盖组件行为的非 DOM prop。需要说明的是从当前仓库源码检索看childElementProps这一具体命名尚未在组件实现中找到同名用法该条目属于规范层面对“组合型组件如何开放内部子元素定制”给出的设计模式建议理解它有助于预判组合型组件 API 的演进方向。通用 Prop 名称Common Prop Names规范要求跨组件复用通用的 prop 名称与共享 API。规范正文列出的通用 prop 取值表如下variant a | b // options dependent on component isQuiet, isEmphasized density compact | regular | spacious orientation horizontal | vertical size XS | S | M | L | XL align start | end labelPosition top | side isIndeterminate注意align使用start | end而非left | right与前述方向无关命名规则首尾呼应labelPosition top | side中的side同理不绑定绝对方向。而规范的最后一句“复用共享 API”指向仓库中的 specs/api/Shared.md其内容分为三组Inputs输入类interface InputBase { isDisabled?: boolean, isRequired?: boolean, validationState?: valid | invalid, isReadOnly?: boolean, autoFocus?: boolean } interface ValueBaseT { value?: T, defaultValue?: T, onChange?: (value: T, e?: Event) void, } interface TextInputBase { placeholder?: string } interface RangeValueT { start: T, end: T } interface RangeInputBaseT { minValue?: T, maxValue?: T, step?: T } type LabelPosition top | side; type Alignment start | end; type NecessityIndicator icon | label; interface Labelable { label?: ReactNode, isRequired?: boolean, labelPosition?: LabelPosition, labelAlign?: Alignment, necessityIndicator?: NecessityIndicator }Selection选择类SelectionOptionsallowsSelection、allowsMultipleSelection、allowsEmptySelection、MultipleSelectionBaseselectedItems/defaultSelectedItems/onSelectionChange、SingleSelectionBaseselectedItem/defaultSelectedItem/onSelectionChange完整演示了allows前缀、default前缀与on...Change命名规则的联动。Drag and Drop拖放类定义了DropOperationMOVE/COPY/LINK 位掩码、DropPositionON/BETWEEN 位掩码、DragDelegate、DropDelegate、DataTransferDelegate与ClipboardDelegate等委托接口。其中renderDragView印证了 render prop 命名与传参规则DropTarget.value则呼应“值优于索引”的原则value: null表示整个树/表格配合dropPosition描述落点。小结如何把规范用到实处这套规范的价值在于把“API 设计”从个人经验变成了可审查的清单。结合仓库的目录组织可以形成这样的实践路径设计新组件 API 前先通读 specs/api/Guidelines.md逐条对照布尔属性前缀is/allows/show/should、事件命名on 现在时 Change结尾、start/end方向命名等规则复用共享基线从 specs/api/Shared.md 中选取适用的接口InputBase、ValueBase、Labelable等保证value/defaultValue/onChange、minValue/maxValue等命名与全库一致对照既有组件规格如 Button.md、TextFields.md、Table.md确认取值范围再看对应实现文件如 RangeSlider.tsx验证受控/非受控与透传逻辑的实际写法。遵循这套准则组件 API 才能在可预测性、可扩展性如validationState的多值演进、start/end的 RTL 翻转与可组合性之间保持长期一致。【免费下载链接】react-spectrumA collection of libraries and tools that help you build adaptive, accessible, and robust user experiences.项目地址: https://gitcode.com/GitHub_Trending/re/react-spectrum创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表