- 前端
- UI组件
【免费下载链接】formily
📱🚀 🧩 Cross Device & High Performance Normal Form/Dynamic(JSON Schema) Form/Form Builder -- Support React/React Native/Vue 2/Vue 3
Space 是 @formily/next 中基于 Flex 布局的轻量排版组件,用于将任意元素快速并排或纵向排列,是表单内“姓名分栏输入”“单位拼接”等场景的常用工具。阅读本文后,你将掌握 Space 的三种 Schema 写法(Markup Schema / JSON Schema / Pure JSX)、完整 API 参数语义,以及它与 FormLayout.spaceGap 联动、默认尺寸映射等底层实现原理。
Space 组件在 Formily 生态中承担着“无数据节点编排”的职责:它本身不绑定任何表单字段,而是作为一个纯布局容器,将多个字段横向或纵向排布在同一视觉行内。与FormGrid(栅格系统)不同,Space 关注的是紧凑、等间距的元素序列,非常适合姓 + 名、单位 + 数值、多个附加后缀输入框等场景。
一、组件定位:Void 节点上的布局容器
从源码结构看,Space 是一个不产生字段值的布局组件。在 packages/next/src/space/index.tsx 中,它接收children后通过toArray将子元素展开,并为每个子元素包裹space-item容器:
{toArray(props.children, { keepEmpty: true }).map((child, index) => ( <div className={`${prefix}-item`} key={index}> {child} </div> ))}因此在使用时,Space 必须挂载在VoidField / void 类型节点上(x-component="Space"),其子节点才是真正参与表单的字段。这保证了布局节点不会污染表单数据模型,是 Formily “布局与数据分离”设计理念的典型体现。
二、Markup Schema 用法
Markup Schema 是 Formily React 中最直观的声明式写法。将Space注册进createSchemaField的 components 后,即可在SchemaField.Void上使用:
import React from 'react' import { Input, FormItem, FormLayout, FormButtonGroup, Submit, Space, } from '@formily/next' import { createForm } from '@formily/core' import { FormProvider, createSchemaField } from '@formily/react' const SchemaField = createSchemaField({ components: { Input, FormItem, Space, }, }) const form = createForm() export default () => ( <FormProvider form={form}> <FormLayout labelCol={6} wrapperCol={16}> <SchemaField> <SchemaField.Void title="name" x-decorator="FormItem" x-decorator-props={{ asterisk: true, feedbackLayout: 'none', }} x-component="Space" > <SchemaField.String name="firstName" x-decorator="FormItem" x-component="Input" required /> <SchemaField.String name="lastName" x-decorator="FormItem" x-component="Input" x-visible="{{$values.firstName === '123'}}" required /> <SchemaField.String name="kk" x-decorator="FormItem" x-component="Input" x-decorator-props={{ addonAfter: 'Unit', }} required /> </SchemaField.Void> <SchemaField.Void title="Text concatenation" x-decorator="FormItem" x-decorator-props={{ asterisk: true, feedbackLayout: 'none', }} x-component="Space" > <SchemaField.String name="aa" x-decorator="FormItem" x-component="Input" x-decorator-props={{ addonAfter: 'Unit', }} required /> <SchemaField.String name="bb" x-decorator="FormItem" x-component="Input" x-decorator-props={{ addonAfter: 'Unit', }} required /> <SchemaField.String name="cc" x-decorator="FormItem" x-component="Input" x-decorator-props={{ addonAfter: 'Unit', }} required /> </SchemaField.Void> <SchemaField.String name="textarea" title="text box" x-decorator="FormItem" required x-component="Input.TextArea" x-component-props={{ style: { width: 400, }, }} /> </SchemaField> <FormButtonGroup.FormItem> <Submit onSubmit={console.log}>Submit</Submit> </FormButtonGroup.FormItem> </FormLayout> </FormProvider> )要点解析:
- 每个
SchemaField.Void用x-component="Space"声明布局容器,x-decorator="FormItem"让整个 Space 拥有统一的标签与校验反馈区域; - 子字段通过
name独立绑定表单数据,彼此互不影响; x-visible="{{$values.firstName === '123'}}"演示了字段联动:当 firstName 的值等于'123'时,lastName 才显示,这验证了 Space 内的字段依然完整参与 Formily 的响应式联动体系;addonAfter: 'Unit'用于给输入框追加单位后缀,形成“数值 + 单位”的拼接观感。
三、JSON Schema 用法
当 Schema 以纯 JSON 形式存在(如后端下发、动态渲染)时,Space 的声明方式转换为type: 'void'+'x-component': 'Space':
import React from 'react' import { Input, FormItem, FormLayout, FormButtonGroup, Submit, Space, } from '@formily/next' import { createForm } from '@formily/core' import { FormProvider, createSchemaField } from '@formily/react' const SchemaField = createSchemaField({ components: { Input, FormItem, Space, }, }) const form = createForm() const schema = { type: 'object', properties: { name: { type: 'void', title: 'Name', 'x-decorator': 'FormItem', 'x-decorator-props': { asterisk: true, feedbackLayout: 'none', }, 'x-component': 'Space', properties: { firstName: { type: 'string', 'x-decorator': 'FormItem', 'x-component': 'Input', required: true, }, lastName: { type: 'string', 'x-decorator': 'FormItem', 'x-component': 'Input', required: true, }, }, }, texts: { type: 'void', title: 'Text concatenation', 'x-decorator': 'FormItem', 'x-decorator-props': { asterisk: true, feedbackLayout: 'none', }, 'x-component': 'Space', properties: { aa: { type: 'string', 'x-decorator': 'FormItem', 'x-decorator-props': { addonAfter: 'Unit', }, 'x-component': 'Input', required: true, }, bb: { type: 'string', 'x-decorator': 'FormItem', 'x-decorator-props': { addonAfter: 'Unit', }, 'x-component': 'Input', required: true, }, cc: { type: 'string', 'x-decorator': 'FormItem', 'x-decorator-props': { addonAfter: 'Unit', }, 'x-component': 'Input', required: true, }, }, }, textarea: { type: 'string', title: 'Text box', 'x-decorator': 'FormItem', 'x-component': 'Input.TextArea', 'x-component-props': { style: { width: 400, }, }, required: true, }, }, } export default () => ( <FormProvider form={form}> <FormLayout labelCol={6} wrapperCol={16}> <SchemaField schema={schema} /> <FormButtonGroup.FormItem> <Submit onSubmit={console.log}>Submit</Submit> </FormButtonGroup.FormItem> </FormLayout> </FormProvider> )JSON Schema 与 Markup Schema 在语义上完全等价:type: 'void'对应 Markup 中的SchemaField.Void,properties对应 JSX 子节点。这种等价性让同一份表单既能静态写在 JSX 里,也能由后端动态下发渲染,是 Formily 动态表单能力的核心。
四、Pure JSX 用法
如果不想使用 Schema 体系,可以直接用@formily/react的Field/VoidField以命令式 JSX 构建等价表单:
import React from 'react' import { Input, FormItem, FormLayout, FormButtonGroup, Submit, Space, } from '@formily/next' import { createForm } from '@formily/core' import { FormProvider, Field, VoidField } from '@formily/react' const form = createForm() export default () => ( <FormProvider form={form}> <FormLayout labelCol={6} wrapperCol={16}> <VoidField name="name" title="name" decorator={[ FormItem, { asterisk: true, feedbackLayout: 'none', }, ]} component={[Space]} > <Field name="firstName" decorator={[FormItem]} component={[Input]} required /> <Field name="lastName" decorator={[FormItem]} component={[Input]} required /> </VoidField> <VoidField name="texts" title="Text concatenation" decorator={[ FormItem, { asterisk: true, feedbackLayout: 'none', }, ]} component={[Space]} > <Field name="aa" decorator={[ FormItem, { addonAfter: 'Unit', }, ]} component={[Input]} required /> <Field name="bb" decorator={[ FormItem, { addonAfter: 'Unit', }, ]} component={[Input]} required /> <Field name="cc" decorator={[ FormItem, { addonAfter: 'Unit', }, ]} component={[Input]} required /> </VoidField> <Field name="textarea" title="text box" decorator={[FormItem]} component={[ Input.TextArea, { style: { width: 400, }, }, ]} required /> <FormButtonGroup.FormItem> <Submit onSubmit={console.log}>Submit</Submit> </FormButtonGroup.FormItem> </FormLayout> </FormProvider> )Pure JSX 写法中,VoidField的component={[Space]}声明布局组件,decorator={[FormItem, {...}]}声明装饰器及参数,Field的component={[Input]}声明字段组件。它与 Schema 写法共享同一个底层字段模型,三种写法可在同一表单中混用。
五、API 详解与源码级实现原理
5.1 属性总览
Space 的属性定义位于 packages/next/src/space/index.tsx 的ISpaceProps接口,完整参数如下:
| 属性名 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| style | CSSProperties | 自定义样式 | - |
| className | string | 自定义 class 名 | - |
| prefix | string | 样式前缀 | true |
| size | number \|'small' \|'large' \|'middle' | 子元素间隔大小 | 8px |
| direction | 'horizontal' \|'vertical' | 排列方向 | 'horizontal' |
| align | 'start' \|'end' \|'center' \|'baseline' | 交叉轴对齐方式 | 'start' |
| wrap | boolean | 是否自动换行 | false |
5.2 size:间隔尺寸的三种解析路径
size的解析逻辑直接体现了 Space 与 FormLayout 的联动设计:
const spaceSize = { small: 8, middle: 16, large: 24, } const _size = size ?? layout?.spaceGap ?? 8- 显式传值:传入数字(如
size={12})时直接作为间隔像素;传入枚举字符串时通过spaceSize映射(small=8px、middle=16px、large=24px); - 继承 FormLayout:未传
size时,自动读取useFormLayout()返回的spaceGap,即上层 FormLayout 的spaceGap?: number配置(见其IFormLayoutProps接口),实现整表统一间距; - 兜底默认值:两层都没有时回退到
8px。
最终间隔通过isNumberLike判定后传给@alifd/next的Box组件的spacing属性落地。
5.3 direction 与 align:Flex 方向与对齐
direction与align会被转换为 Box 的 Flex 语义:
const getDirection = () => (direction === 'horizontal' ? 'row' : 'column') const getAlign = () => { if (align === 'start') return 'flex-start' if (align === 'end') return 'flex-end' return 'center' }direction='horizontal'→row(横向并排,默认),vertical→column(纵向堆叠);align映射到 Flex 的align-items:start→flex-start(默认)、end→flex-end、center→center,baseline交由 Box 原生处理;- 容器根元素强制
display: 'inline-flex',因此 Space 可以像内联元素一样被嵌入到文本流或按钮组中,同时内部保持 Flex 布局。
5.4 prefix 与样式细节
usePrefixCls('space', props)生成space样式前缀(可通过prefix覆盖),每个子元素被包裹在<div class="xxx-space-item">中。对应样式 packages/next/src/space/main.scss 只有一个关键规则:
.#{$space-prefix-cls}-item:empty { display: none !important; }即空子元素自动隐藏。这意味着当联动导致某个字段被隐藏(如示例中 lastName 的x-visible条件不满足)时,它在 Space 中不会留下空白占位,布局不会出现空洞。样式入口见 packages/next/src/space/style.ts,它引入@alifd/next/lib/box/style与main.scss。
5.5 与 FormLayout 的联动:spaceGap
这是 Space 最值得关注的继承特性:在 packages/next/src/form-layout/index.tsx 中,FormLayout通过FormLayoutDeepContext/FormLayoutShallowContext双层 Context 向下传递布局配置(useFormLayout合并两层取值),spaceGap正是其中之一。因此你可以在FormLayout上统一设置:
<FormLayout spaceGap={12}> {/* 所有未显式传 size 的 Space 都会使用 12px 间隔 */} </FormLayout>从源码结构看,这保证了“整表间距统一”只需一处配置即可生效,而单个 Space 仍可通过自身size覆盖全局值,兼顾全局一致性与局部定制。
5.6 多端实现对照
需要说明的是,Space 在各 UI 库适配包中均有实现,且保持一致的 API 心智:
- @formily/antd(packages/antd/src/space/index.tsx):直接透传 antd 的
Space组件,同样接入useFormLayout的spaceGap作为默认size; - @formily/next(本文主体):基于
@alifd/next的Box封装,增加direction、align、wrap等语义化参数。
两者共享同一套size ?? spaceGap取值策略,切换 UI 库时无需改动业务用法。
六、典型使用建议
- 姓名分栏:姓、名分别作为 Space 子字段,保持独立校验与数据键;
- 数值 + 单位:利用
addonAfter在输入框后拼接单位,多个字段并排形成“测量值序列”; - 联动隐藏:结合
x-visible表达式动态显隐子字段,配合space-item:empty的隐藏规则,布局自动收拢,无需手动管理占位; - 整表间距:优先通过
FormLayout.spaceGap统一配置,局部再以size覆盖,避免重复书写间距。
结语
Space 是 Formily 表单布局体系中“小而美”的一环:它用最小的 API 表面(7 个属性)覆盖了并排、纵排、对齐、换行与间距继承等日常布局需求,同时通过 Void 节点与 Flex 容器的组合,与 Formily 的联动、校验、数据模型体系无缝协作。理解它的实现(packages/next/src/space/index.tsx)与 FormLayout 的 Context 联动机制,能帮助你在实际表单项目中更准确地选择布局方案——当需要栅格化的复杂排布时选用FormGrid,当只需要紧凑的元素序列时,Space 就是最直接的选择。
- 前端
- UI组件
【免费下载链接】formily
📱🚀 🧩 Cross Device & High Performance Normal Form/Dynamic(JSON Schema) Form/Form Builder -- Support React/React Native/Vue 2/Vue 3
相关推荐
Formily Next Space 组件完全指南:用 Flex 布局快速实现表单元素并排与文本串联
Formily Next Space 组件完全指南:用 Flex 布局快速实现表单元素并排与文本串联 本文以 @formily/next 中的 Space 组件
前端UI组件Formily Space 组件实战指南(antd 版):三种 Schema 模式实现表单元素并排布局
Formily Space 组件实战指南(antd 版):三种 Schema 模式实现表单元素并排布局 Space 是 Formily 在 @formily/a
前端UI组件@formily/antd Space 组件完全指南:三种 Schema 写法的 Flex 并排布局实战
@formily/antd Space 组件完全指南:三种 Schema 写法的 Flex 并排布局实战 Space 是 Formily 体系中一个"超级便捷的
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考