前端UI组件【免费下载链接】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 体系中formily/next的 Radio 组件文档为核心系统讲解如何在表单中实现单选功能。你将掌握 Markup Schema、JSON Schema、纯 JSX 三种声明方式下 Radio 的完整用法理解enum/dataSource选项数据的映射机制并深入connect/mapProps/mapReadPretty等源码层实现搞清楚单选值如何与表单模型双向同步、如何自动支持只读预览从而在实际项目中游刃有余地选用最合适的写法。一、组件定位Formily 中的单选组件Radio单选框是表单中最基础的选择类组件之一用于在若干互斥选项中仅选取一项。在 Formily 体系中各 UI 库适配层均提供了统一的Radio组件接口但它们底层渲染的具体控件不同formily/next基于阿里巴巴 Fusion Nextformily/antd基于 Ant Design 的Radio源码位于 packages/antd/src/radio/index.tsxformily/element基于 Element UI 的Radio/RadioButton源码位于 packages/element/src/radio/index.ts。本文以 packages/next/docs/components/Radio.md 文档为主展开其余实现作为对照参考。所有适配层都遵循同一个设计模式把第三方 UI 组件的 Props 通过connect桥接到 Formily 的字段模型上因此无论你使用哪套组件库写法与行为都高度一致。文档中组件被定义为 Single selection box单选选择框并声明了两种形态形态说明Radio单个单选项对应底层NextRadio/AntdRadio/ElRadioRadio.Group单选组对应底层NextRadio.Group/AntdRadio.Group/ElRadioGroup配合选项数据一次性渲染一组单选在实际业务中Radio.Group是更常用的形态因为它直接对接选项数据源与表单字段的值绑定。二、Markup Schema 写法声明式组件树Markup Schema 是 Formily 在 JSX 内部书写 JSON Schema 的 DSL 形式。它把 Schema 节点写成组件标签如SchemaField.Number /由编译器在运行时转换回标准 Schema 结构。文档中的示例完整代码如下源码见 packages/next/docs/components/Radio.mdimport React from react import { Radio, FormItem, FormButtonGroup, Submit } from formily/next import { createForm } from formily/core import { FormProvider, createSchemaField } from formily/react const SchemaField createSchemaField({ components: { Radio, FormItem, }, }) const form createForm() export default () ( FormProvider form{form} SchemaField SchemaField.Number nameradio titlesingle choice enum{[ { label: Option 1, value: 1, }, { label: Option 2, value: 2, }, ]} x-decoratorFormItem x-componentRadio.Group / /SchemaField FormButtonGroup Submit onSubmit{console.log}Submit/Submit /FormButtonGroup /FormProvider )关键点拆解注册组件createSchemaField({ components: { Radio, FormItem } })将Radio与FormItem注册进 SchemaField 的组件映射表这样x-componentRadio.Group和x-decoratorFormItem才能在运行时被正确解析。字段类型SchemaField.Number表明该字段的数据类型为number这也是单选值常用的类型选项 value 为 1、2。选项数据enum属性传入{ label, value }结构数组。在 Schema 编译阶段enum会被自动映射为字段的dataSource见后文「enum 与 dataSource 的映射原理」最终透传给Radio.Group渲染。装饰器与组件x-decoratorFormItem表示用 FormItem 包裹负责布局、标签、校验错误展示x-componentRadio.Group指定渲染单选组。提交Submit配合FormButtonGroup组成提交按钮onSubmit{console.log}会在提交时打印表单值此时form.values中的radio字段即为选中项的 value如1或2。三、JSON Schema 写法纯数据驱动JSON Schema 写法与 Markup Schema 在语义上完全等价只是把 Schema 从 JSX 中抽离为独立的 JSON 对象适合动态化、服务端下发的场景。文档示例见 packages/next/docs/components/Radio.mdimport React from react import { Radio, FormItem, FormButtonGroup, Submit } from formily/next import { createForm } from formily/core import { FormProvider, createSchemaField } from formily/react const SchemaField createSchemaField({ components: { Radio, FormItem, }, }) const form createForm() const schema { type: object, properties: { radio: { type: number, title: Single selection, enum: [ { label: Option 1, value: 1, }, { label: Option 2, value: 2, }, ], x-decorator: FormItem, x-component: Radio.Group, }, }, } export default () ( FormProvider form{form} SchemaField schema{schema} / FormButtonGroup Submit onSubmit{console.log}Submit/Submit /FormButtonGroup /FormProvider )与 Markup Schema 的差异仅在声明形式上Markup 写法用SchemaField.Number nameradio ... /JSON 写法用properties.radio { type: number, ... }。两者在运行时生成完全一致的字段模型。createSchemaField负责将 JSON Schema 编译为可被formily/react消费的内部结构enum同样会被转换为dataSource注入字段。四、纯 JSX 写法完全编程式控制如果不需要 Schema 的声明式能力例如选项数据来自运行时计算、或需要精细控制组件 Props可以直接使用Field组件以 JSX 方式编写。文档示例见 packages/next/docs/components/Radio.mdimport React from react import { Radio, FormItem, FormButtonGroup, Submit } from formily/next import { createForm } from formily/core import { FormProvider, Field } from formily/react const form createForm() export default () ( FormProvider form{form} Field nameradio titlesingle choice dataSource{[ { label: Option 1, value: 1, }, { label: Option 2, value: 2, }, ]} decorator{FormItem} component{Radio.Group} / FormButtonGroup Submit onSubmit{console.log}Submit/Submit /FormButtonGroup /FormProvider )注意纯 JSX 写法与 Schema 写法的对应关系Schema 属性JSX 属性说明enumdataSource选项数据源JSX 中直接使用字段模型的概念x-decoratorFormItemdecorator{FormItem}装饰器组件直接传组件引用而非字符串x-componentRadio.Groupcomponent{Radio.Group}渲染组件直接传组件引用Field组件把name、title、dataSource等属性写入字段模型并将Radio.Group作为实际渲染组件同时由FormItem装饰。三者中纯 JSX 写法最贴近传统 React 组件用法也是理解connect原理最直观的入口。五、enum 与 dataSource 的映射原理为什么 Schema 里写的是enum而 JSX 里写的是dataSource这是 Formily 刻意设计的标准 JSON Schema 关键字到内部状态模型的关键字映射。在 packages/json-schema/src/shared.ts 中定义了SchemaStateMapexport const SchemaStateMap { title: title, description: description, default: initialValue, enum: dataSource, // ← enum 映射为 dataSource readOnly: readOnly, writeOnly: editable, x-content: content, x-data: data, x-value: value, x-editable: editable, x-disabled: disabled, x-read-pretty: readPretty, x-read-only: readOnly, x-visible: visible, x-hidden: hidden, x-display: display, x-pattern: pattern, x-validator: validator, x-decorator: decoratorType, x-component: componentType, x-decorator-props: decoratorProps, x-component-props: componentProps, }Schema 编译时enum键会被翻译为字段状态中的dataSource。同文件中的patchStateFormSchemapackages/json-schema/src/shared.ts进一步处理了enum数组的标准化const isEnum key enum isArr(compiled) // ... isEnum ? createDataSource(compiled) : compiled而createDataSourcepackages/json-schema/src/shared.ts会把纯字符串/数字数组自动包装成{ label, value }结构export const createDataSource (source: any[]) { return toArr(source).map((item) { if (typeof item object) { return item } else { return { label: item, value: item, } } }) }这意味着你既可以写enum{[{ label: Option 1, value: 1 }]}这样的完整对象数组也可以简写为enum{[Option 1, Option 2]}后者会被自动补齐为{ label: Option 1, value: Option 1 }。这与formily/next组件层mapProps({ dataSource: true })的透传配合最终将标准化的选项数组送入 Fusion Next 的Radio.Group。六、组件源码解析connect 如何打通双向绑定Radio与Radio.Group的本质是formily/react的connect高阶组件包装。以 packages/next/src/radio/index.tsx 为例export const Radio: ComposedRadio connect( NextRadio, mapProps( { value: checked, }, mapSize ) ) Radio.Group connect( NextRadio.Group, mapProps( { dataSource: true, }, mapSize ), mapReadPretty(PreviewText.Select) )1. 单个 Radio 的 value → checked 映射mapProps({ value: checked })将 Formily 字段模型的value映射为 Fusion Next 单选项的checkedprop。单个Radio通常用于固定布尔型或独立开关场景如是否同意协议选中时checked true会通过onChange回写字段值。2. Radio.Group 的 dataSource 透传与尺寸联动mapProps({ dataSource: true })表示将字段的dataSource原样透传给Radio.Group。结合上文可知无论选项来自 Schema 的enum还是 JSX 的dataSource最终都会落在这个属性上。第二个映射mapSize来自 packages/next/src/builtins/mapSize.tsexport const mapSize (props: any) { const layout { ...useFormShallowLayout(), ...useFormLayout() } const takeSize () { return layout.size default ? medium : layout.size } return { ...props, size: props.size || takeSize(), } }mapSize从表单布局上下文FormLayout读取全局尺寸配置并注入组件使 Radio 能跟随表单统一调整大小small/medium/large无需在每个组件上手动声明。这正是 Formily 全局布局能力的体现详见 packages/next/src/form-layout/index.tsx。3. mapReadPretty自动只读预览mapReadPretty(PreviewText.Select)是单选组在只读态如详情页、表单回显下的关键实现。当字段处于readPretty模式时connect会自动用PreviewText.Select替换Radio.Group的渲染。PreviewText.Select的实现位于 packages/next/src/preview-text/index.tsxconst Select: React.FCReact.PropsWithChildrenSelectProps observer( (props) { const field useFieldField() // ... const dataSource: any[] field?.dataSource?.length ? field.dataSource : props?.dataSource?.length ? props.dataSource : [] const placeholder usePlaceholder() const getLabel (target: any) { return ( dataSource?.find((item) item.value target?.value)?.label || target.label || placeholder ) } // ... return div className{cls(prefixCls, props.className)}{getLabels()}/div } )它通过useField读取字段模型上的dataSource把当前选中的value反查为对应的label并以纯文本渲染无值时显示默认占位符N/A。这样在只读场景下单选值展示为可读文案而非被禁用的控件。占位符可通过PreviewText.Placeholder全局定制例如设置为暂无。4. Antd 版本对照packages/antd/src/radio/index.tsx 与 Next 版本高度一致差异仅在适配层细节export const Radio: ComposedRadio connect( AntdRadio, mapProps({ value: checked, }) ) Radio.__ANT_RADIO true Radio.Group connect( AntdRadio.Group, mapProps({ dataSource: options, // Antd 的选项属性名是 options }), mapReadPretty(PreviewText.Select) )Antd 版本额外设置了Radio.__ANT_RADIO true标记供内部逻辑识别组件来源dataSource: options将字段的dataSource映射为 Antd Radio.Group 的options属性而 Next 版本是dataSource: true原样透传——这是两套组件库 API 差异在适配层被抹平的直接证据只读预览同样使用PreviewText.Select对应实现在 packages/antd/src/preview-text/index.tsx额外支持fieldNames自定义label/value字段名。Element 版本Vue 场景见 packages/element/src/radio/index.ts它额外实现了options渲染逻辑与optionType: default | button的按钮形态切换RadioButton且选项值为label同样以mapProps({ dataSource: options })与mapReadPretty(PreviewText.Select)完成桥接。七、API 说明与扩展属性文档末尾给出的 API 说明为Reference https://fusion.design/pc/component/basic/radio即formily/next的Radio直接继承 Fusion Next Radio 的完整 API包括Radio.Group的dataSource、value、onChange、disabled、size等全部属性。Formily 适配层不改变底层组件的 API 语义只是把字段的值/数据源/状态与组件对接因此底层组件的任何能力如Radio.Group的方向布局、按钮样式等均可直接使用。在此基础上Formily 还叠加了下列由适配层提供的增强能力能力实现机制说明字段值双向同步connectmapProps({ value: checked })选中状态与字段模型value实时同步选项数据自动注入mapProps({ dataSource: true / options })从字段dataSource映射到底层组件的选项属性尺寸联动mapSize仅 Next跟随FormLayout全局尺寸自动调整只读预览mapReadPretty(PreviewText.Select)readPretty模式下渲染为纯文本 label校验与错误展示x-decoratorFormItem的字段联动单选必选校验通过 FormItem 呈现必选校验示例结合FormItem装饰器只需为字段声明required即可启用单选必选校验SchemaField.Number nameradio titlesingle choice required enum{[ { label: Option 1, value: 1 }, { label: Option 2, value: 2 }, ]} x-decoratorFormItem x-componentRadio.Group /未选择任何选项时提交FormItem 会展示该字段必填的校验提示Submit也不会触发onSubmit回调。八、三种写法的选型建议写法适用场景优势注意点Markup Schema常规表单开发希望 Schema 与 JSX 共处类型友好、IDE 提示好、可读性高需createSchemaField注册组件JSON Schema动态表单、服务端下发 Schema、低代码平台纯数据可序列化、易于持久化与远程传输Schema 需自行维护与校验纯 JSX逻辑复杂、选项运行时计算、精细控制组件无 Schema 心智负担、最接近原生 React 用法数据源需显式传dataSource三者最终都会汇入formily/core的字段模型通过FormProvider共享同一个form实例因此校验、联动、提交等能力完全一致可以在同一表单内混用。九、小结本文围绕 packages/next/docs/components/Radio.md 的三个完整示例完整呈现了formily/next中 Radio 单选框的三种声明方式Markup SchemaSchemaField.Number x-componentRadio.Group enum{...} /JSON Schemaproperties.radio { type: number, enum: [...], x-component: Radio.Group }纯 JSXField component{Radio.Group} dataSource{...} /。并从源码层验证了三个关键机制enum → dataSource的标准 JSON Schema 关键字映射packages/json-schema/src/shared.ts、connect/mapProps/mapSize的双向绑定与尺寸联动packages/next/src/radio/index.tsx、packages/next/src/builtins/mapSize.ts、以及mapReadPretty(PreviewText.Select)的只读文本预览packages/next/src/preview-text/index.tsx。这些机制在formily/antd、formily/element中同样成立只是底层映射的组件属性名略有差异。掌握了 Radio 的用法也就掌握了 Formily 中所有选项型组件Select、Checkbox、Cascader 等的通用接入范式——它们共享同一套dataSource数据契约与connect桥接模型可以举一反三。赞分享前端UI组件【免费下载链接】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 Next 的 Radio 单选框组件三种 Schema 写法与源码级封装解析Formily Next 的 Radio 单选框组件三种 Schema 写法与源码级封装解析 本文基于 Formily 2.x 的 formily/next前端UI组件Formily Next 复选框组件 Checkbox 完全使用指南Markup Schema / JSON Schema / Pure JSX 三种写法与源码原理Formily Next 复选框组件 Checkbox 完全使用指南Markup Schema / JSON Schema / Pure JSX 三种写法与源前端UI组件Formily 复选框组件 Checkbox 完全指南Markup Schema / JSON Schema / JSX 三种用法与源码级桥接原理Formily 复选框组件 Checkbox 完全指南Markup Schema / JSON Schema / JSX 三种用法与源码级桥接原理 本文围绕前端UI组件创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
