
Formily 复选框组件 Checkbox 完全指南Markup Schema / JSON Schema / JSX 三种用法与源码级桥接原理【免费下载链接】formily Cross Device High Performance Normal Form/Dynamic(JSON Schema) Form/Form Builder -- Support React/React Native/Vue 2/Vue 3项目地址: https://gitcode.com/gh_mirrors/fo/formily本文围绕 Formily 2.xformily/antd2.3.7中封装自 Ant Design 的复选框组件Checkbox完整讲解单复选框Checkbox与复选组Checkbox.Group在Markup Schema、JSON Schema、纯 JSX三种编程模式下的接入方式并结合仓库源码剖析其背后的connect/mapProps/mapReadPretty桥接机制、enum → dataSource的数据源映射原理以及只读预览实现帮助你在实际项目中正确选型并理解 Formily 组件封装规范。一、组件概览Checkbox与Checkbox.Group在 Formily 的 Ant Design 协议组件集中复选框组件由 packages/antd/src/checkbox/index.tsx 导出它是一个组合式组件同时提供两种形态Checkbox单个复选框对应布尔类型字段boolean表单值类型为true / falseCheckbox.Group复选框组对应数组类型字段array表单值类型为选中项的value数组。从源码看整个组件只有不到 30 行核心封装逻辑完全依赖formily/react提供的三个高阶封装函数import { connect, mapProps, mapReadPretty } from formily/react import { Checkbox as AntdCheckbox } from antd import { CheckboxProps, CheckboxGroupProps } from antd/lib/checkbox import { PreviewText } from ../preview-text type ComposedCheckbox React.FCReact.PropsWithChildrenCheckboxProps { Group?: React.FCReact.PropsWithChildrenCheckboxGroupProps __ANT_CHECKBOX?: boolean } export const Checkbox: ComposedCheckbox connect( AntdCheckbox, mapProps({ value: checked, }) ) Checkbox.__ANT_CHECKBOX true Checkbox.Group connect( AntdCheckbox.Group, mapProps({ dataSource: options, }), mapReadPretty(PreviewText.Select, { mode: tags, }) ) export default Checkbox这段源码可以拆解出三个关键事实字段值到组件 props 的映射单选框通过mapProps({ value: checked })把 Formily 字段的value状态映射为 antdCheckbox的checkedpropantd 单选框接收checked而非value数据源映射Checkbox.Group通过mapProps({ dataSource: options })把字段的dataSource状态映射为 antdCheckbox.Group的optionsprop因此你在 Schema 中写的enum最终会流入options渲染出选项列表只读预览mapReadPretty(PreviewText.Select, { mode: tags })指定了当字段处于readPretty阅读态时用PreviewText.Select以tags标签形式渲染已选值。此外组件还挂载了__ANT_CHECKBOX标记供 Formily 内部例如某些自动化推导逻辑识别组件类型。样式方面packages/antd/src/checkbox/style.ts 只做了一件事——引入 antd 官方 checkbox 样式import antd/lib/checkbox/style/index组件整体从 packages/antd/src/index.ts 第 24 行export * from ./checkbox统一导出因此你可以从formily/antd顶层直接引入。环境前提formily/antd的peerDependencies声明了antd 4.22.8、react 16.8.0详见 packages/antd/package.json请确保项目依赖版本与之匹配。二、三种使用模式任选其一Formily 为同一组件提供了三种等价的声明方式。下面三节完整继承自原文档 Checkbox.zh-CN.md你可以直接复制运行三种模式最终渲染出的界面与提交的数据结构完全一致。1. Markup Schema 案例Markup Schema 是 Formily 最推荐、书写最直观的 Schema 方式直接在 JSX 中通过SchemaField.Boolean/SchemaField.String等标签声明字段结构x-decorator指定装饰器FormItemx-component指定组件Checkbox/Checkbox.Group。import React from react import { Checkbox, FormItem, FormButtonGroup, Submit } from formily/antd import { createForm } from formily/core import { FormProvider, createSchemaField } from formily/react const SchemaField createSchemaField({ components: { Checkbox, FormItem, }, }) const form createForm() export default () ( FormProvider form{form} SchemaField SchemaField.Boolean namesingle title是否确认 x-decoratorFormItem x-componentCheckbox / SchemaField.String namemultiple title复选 enum{[ { label: 选项1, value: 1, }, { label: 选项2, value: 2, }, ]} x-decoratorFormItem x-componentCheckbox.Group / /SchemaField FormButtonGroup Submit onSubmit{console.log}提交/Submit /FormButtonGroup /FormProvider )要点解读SchemaField.Boolean对应type: boolean字段配合x-componentCheckbox生成单个复选框表单值single提交时是true / falseSchemaField.String字段类型虽然是字符串但配合enum与x-componentCheckbox.Group时会被当作数组复选字段处理enum中每个{ label, value }对象声明一个选项提交时multiple是选中项的value数组enum直接写在 JSX 属性上即可无需额外的x-component-props配置。2. JSON Schema 案例JSON Schema 模式把 Schema 定义为纯 JSON 对象通过SchemaField schema{schema} /一次性传入适合 Schema 来自后端接口或需要序列化存储的场景。import React from react import { Checkbox, FormItem, FormButtonGroup, Submit } from formily/antd import { createForm } from formily/core import { FormProvider, createSchemaField } from formily/react const SchemaField createSchemaField({ components: { Checkbox, FormItem, }, }) const form createForm() const schema { type: object, properties: { single: { type: boolean, title: 是否确认, x-decorator: FormItem, x-component: Checkbox, }, multiple: { type: array, title: 复选, enum: [ { label: 选项1, value: 1, }, { label: 选项2, value: 2, }, ], x-decorator: FormItem, x-component: Checkbox.Group, }, }, } export default () ( FormProvider form{form} SchemaField schema{schema} / FormButtonGroup Submit onSubmit{console.log}提交/Submit /FormButtonGroup /FormProvider )与 Markup Schema 案例相比这里唯一的结构差异是复选字段的type显式声明为arrayMarkup 模式用SchemaField.String也能推导出数组字段是因为Checkbox.Group的映射约定。enum数组中的label用于展示value用于提交二者均支持字符串、数字等任意可序列化类型。3. 纯 JSX 案例纯 JSX 模式不使用 Schema直接通过formily/react的Field组件声明字段decorator与component都写成「组件 组件 props」的元组形式选项通过dataSource属性传入。import React from react import { Checkbox, FormItem, FormButtonGroup, Submit } from formily/antd import { createForm } from formily/core import { FormProvider, Field } from formily/react const form createForm() export default () ( FormProvider form{form} Field namesingle title是否确认 decorator{[FormItem]} component{[Checkbox]} / Field namemultiple title复选 dataSource{[ { label: 选项1, value: 1, }, { label: 选项2, value: 2, }, ]} decorator{[FormItem]} component{[Checkbox.Group]} / FormButtonGroup Submit onSubmit{console.log}提交/Submit /FormButtonGroup /FormProvider )要点解读component{[Checkbox]}只传组件本身单选框的checked由 Formily 自动从字段value映射无需手动传checked或onChange——这是受控表单的核心价值纯 JSX 模式中字段选项直接叫dataSource与 Schema 中的enum等价下文会解释二者的映射关系decorator{[FormItem]}让FormItem负责标题、错误信息、校验状态等外观层逻辑。三、数据形态与提交结果三个案例最终都通过FormButtonGroup中的Submit组件提交onSubmit回调接收的提交值结构为{ single: true, // boolean单个复选框是否选中 multiple: [1, 2], // array复选组中选中项的 value 集合 }需要记住的规则字段类型组件提交值类型说明booleanCheckboxboolean选中为true未选中为falsearrayCheckbox.GroupArrayvalue未选中任何项时为空数组[]选项项—{ label, value }label仅用于展示value进入表单值如果选项来自接口、需要在初始化时回显可以用initialValue或default预置单选框置true复选组置[1]这类 value 数组。四、源码级原理connect与状态映射桥为什么「Schema 里写enumantd 组件就能拿到options」「字段value会自动变成 antd 的checked」答案在 packages/react/src/shared/connect.ts 中实现的三个函数里。1.connect组合封装器的入口export function connectT extends JSXComponent( target: T, ...args: IComponentMapperT[] ) { const Target args.reduce((target, mapper) { return mapper(target) }, target) // 用 React.forwardRef 包装保证 ref 能透传到底层组件 const Destination React.forwardRef((props, ref) { return React.createElement(Target, { ...props, ref }) }) if (target) hoistNonReactStatics(Destination, target as any) return Destination }它把多个mapper如mapProps、mapReadPretty从左到右依次叠加到底层组件上forwardRef保证 ref 可用hoistNonReactStatics把 antd 组件上的静态属性复制到包装结果上——这正是Checkbox.Group这类静态属性能够保留的原因。2.mapProps字段状态 → 组件 propsexport function mapPropsT extends JSXComponent( ...args: IStateMapperReact.ComponentPropsT[] ) { return (target: T) { return observer((props: any) { const field useField() const results args.reduce((props, mapper) { // ... each(mapper, (to, extract) { const extractValue FormPath.getIn(field, extract) const targetValue isStr(to) ? to : extract if (extract value) { if (to ! extract) delete props.value // 映射后移除原始 value } // ... FormPath.setIn(props, targetValue, extractValue) }) // ... }, { ...props }) return React.createElement(target, results) }, { forwardRef: true }) } }它从useField()拿到字段模型把字段的value、dataSource、disabled等状态按映射表搬运到组件 props 上。对应到 Checkbox 源码mapProps({ value: checked })从字段取value写入组件的checked并删除原来的valueprop避免value与checked同时存在导致 antd 行为异常mapProps({ dataSource: options })从字段取dataSource写入组件的options。3.mapReadPretty阅读态自动切换预览组件export function mapReadPretty(component, readPrettyProps) { return (target) { return observer((props) { const field useField() if (!isVoidField(field) field?.pattern readPretty) { return React.createElement(component, { ...readPrettyProps, ...props }) } return React.createElement(target, props) }, { forwardRef: true }) } }当字段的pattern为readPretty可通过x-pattern: readPretty或字段属性切换时不再渲染可交互的 antd 组件而是渲染PreviewText.Select并把mode: tags混入其 props。于是复选组的阅读态呈现为一排Tag标签而非禁用状态的复选框这在详情页、审批流等只读场景下体验更佳。PreviewText.Select的实现位于 packages/antd/src/preview-text/index.tsx它优先取field.dataSource、其次取props.options来查找label未命中时回退为占位文本N/A。顺带一提同仓库的 Fusion Next 协议组件集在 packages/next/src/checkbox/index.tsx 中提供了几乎对称的封装mapProps({ dataSource: true })直接透传、阅读态预览mode: multiple说明这套「connect 状态映射」规范是 Formily 各 UI 组件库统一的封装范式。五、Schema 的enum是如何变成dataSource的在 Markup/JSON Schema 模式下你写的是enum而mapProps读取的是字段的dataSource中间的转换发生在 JSON Schema 编译阶段。在 packages/json-schema/src/shared.ts 中export const SchemaStateMap { // ... enum: dataSource, // schema 的 enum 映射为字段的 dataSource // ... }编译时patchStateFormSchema会命中该映射第 199–206 行并把enum值交给createDataSource规整export const createDataSource (source: any[]) { return toArr(source).map((item) { if (typeof item object) { return item } else { return { label: item, value: item } } }) }也就是说如果你的enum写的是[{ label, value }]对象数组原样透传为dataSource如果你的enum写的是[选项1, 选项2]这种纯字符串/数字数组也会被自动包装成{ label: item, value: item }label与value相同。因此在 Schema 中你既可以直接写[A, B]偷懒也可以写[{ label: 选项A, value: a }]让展示值与提交值分离例如提交英文 code、展示中文文案。六、API 说明formily/antd的Checkbox/Checkbox.Group是 antdCheckbox与Checkbox.Group的 Formily 封装组件本身的可配置 props 与 antd 完全一致如disabled、checked、onChange、defaultChecked复选组还包括options、value、onChange、disabled等。Formily 层新增的约定 API 如下层级配置项说明Schemax-component-props透传给 antd 组件例如x-component-props{{ disabled: true }}禁用整个复选组Schema字段属性enum声明选项编译后成为字段dataSource再映射为options字段属性value单选框true/false复选组为value数组字段属性dataSource纯 JSX 模式下直接传选项数组字段属性pattern: readPretty阅读态复选组以PreviewText.Select标签形式展示字段属性title/required等由FormItem装饰器渲染为标签、必填星号与校验反馈在实际项目中推荐按需选择需要序列化、后端下发 Schema 时用 JSON Schema 模式追求类型安全与就近可读性时用 Markup Schema 模式组件级拼接或已有 JSX 结构时用纯 JSX 模式。三种模式共享同一套字段模型与状态映射切换成本极低这也是 Formily 分层架构formily/core字段模型 formily/json-schema编译 formily/react桥接带来的核心收益。【免费下载链接】formily Cross Device High Performance Normal Form/Dynamic(JSON Schema) Form/Form Builder -- Support React/React Native/Vue 2/Vue 3项目地址: https://gitcode.com/gh_mirrors/fo/formily创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考