FormItem
FormItem是表单项装饰器,基于 antd-mobile 的List.Item实现,负责标签、校验反馈与帮助文案的渲染。
在 Field 中通过 decorator={[FormItem]} 使用。
提示
FormItem 关于右侧箭头的显示添加了内置逻辑,详情请参考箭头与清除按钮。
基础使用
通过 help 展示常驻帮助文案,字段的 description 展示右侧补充内容。
提示
例子中额外传入了asterisk: false关闭了必填项星号的显示。
import { FormButtonGroup, FormItem, Input, Submit } from '@silver-formily/antd-mobile'
import { createForm } from '@silver-formily/core'
import { Field, FormProvider } from '@silver-formily/react'
const form = createForm()
function onSubmit(values: unknown) {
return Prompts.alert(JSON.stringify(values, null, 2))
}
export default function FormItemBasic() {
return (
<FormProvider form={form}>
<Field
name="username"
title="用户名"
required
decorator={[FormItem, { help: <span>帮助文案会一直展示在表单项下方</span>, asterisk: false }]}
component={[Input, { placeholder: '请输入用户名' }]}
/>
<Field
name="extra"
title="额外内容"
decorator={[FormItem, { extra: '右侧补充' }]}
component={[Input, { placeholder: '请输入补充内容' }]}
/>
<FormButtonGroup>
<Submit onSubmit={onSubmit}>提交</Submit>
</FormButtonGroup>
</FormProvider>
)
}表单校验
配合字段的 validator 使用,校验失败时自动展示错误反馈;required 标记必填并展示星号。
import { FormButtonGroup, FormItem, Input, Submit } from '@silver-formily/antd-mobile'
import { createForm } from '@silver-formily/core'
import { Field, FormProvider } from '@silver-formily/react'
const form = createForm()
function onSubmit(values: unknown) {
return Prompts.alert(JSON.stringify(values, null, 2))
}
export default function FormItemValidation() {
return (
<FormProvider form={form}>
<Field
name="username"
title="用户名"
required
validator={(value) => {
if (!value)
return '请输入用户名'
if (String(value).length < 3)
return '用户名至少 3 个字符'
}}
decorator={[FormItem]}
component={[Input, { placeholder: '请输入至少 3 个字符的用户名' }]}
/>
<Field
name="email"
title="邮箱"
required
validator="email"
decorator={[FormItem]}
component={[Input, { placeholder: '请输入邮箱地址' }]}
/>
<FormButtonGroup>
<Submit onSubmit={onSubmit}>提交</Submit>
</FormButtonGroup>
</FormProvider>
)
}非阻塞校验
validator 返回 { type: 'warning', message } 可产生非阻塞告警,作用类似 antd-mobile 的 warningOnly,但使用的是 Formily 校验接口,无需配置 warningOnly。
设置 validateFirst={false} 让全部规则执行。错误和告警会同时展示,每条消息独占一行,先错误后告警;错误阻塞提交,告警不阻塞提交。
- 输入
ab c:少于 6 个字符且包含空格,同时显示错误和告警,无法提交。 - 输入
hello world:仅显示空格告警,仍可提交并弹窗查看结果。 - 输入
helloworld:无校验反馈,正常提交。
import { FormButtonGroup, FormItem, Input, Submit } from '@silver-formily/antd-mobile'
import { createForm } from '@silver-formily/core'
import { Field, FormProvider } from '@silver-formily/react'
const form = createForm()
function onSubmit(values: unknown) {
return Prompts.alert(JSON.stringify(values, null, 2))
}
export default function NonBlockingValidation() {
return (
<FormProvider form={form}>
<Field
name="username"
title="用户名"
validateFirst={false}
validator={[
(value) => {
if (String(value ?? '').length < 6)
return '用户名至少 6 个字符'
},
(value) => {
if (String(value ?? '').includes(' '))
return { type: 'warning', message: '建议用户名不要包含空格' }
},
]}
decorator={[FormItem]}
component={[Input, { placeholder: '试试 ab c 或 hello world' }]}
/>
<FormButtonGroup>
<Submit onSubmit={onSubmit}>提交</Submit>
</FormButtonGroup>
</FormProvider>
)
}标签配置
labelWidth、labelAlign 可覆盖 FormLayout 下发的布局。下面用户名继承 80px、左对齐;地址覆盖为 120px、右对齐;备注使用 120px、左对齐,并展示点击提示。输入框初始为空,可通过 placeholder 对照控件的起始位置。
横向布局中,labelWidth 控制标签列的内容宽度,标签与控件间另保留 20px 间距;百分比只相对于列表项内容区域计算一次。右对齐保持文字在前、提示图标在后。
import { FormButtonGroup, FormItem, FormLayout, Input, Submit } from '@silver-formily/antd-mobile'
import { createForm } from '@silver-formily/core'
import { Field, FormProvider } from '@silver-formily/react'
const form = createForm()
function onSubmit(values: unknown) {
return Prompts.alert(JSON.stringify(values, null, 2))
}
export default function FormItemLabel() {
return (
<FormProvider form={form}>
<FormLayout labelWidth={80} labelAlign="left">
<Field
name="username"
title="用户名"
required
decorator={[FormItem]}
component={[Input, { placeholder: '请输入用户名' }]}
/>
<Field
name="address"
title="地址"
decorator={[FormItem, {
labelWidth: 120,
labelAlign: 'right',
}]}
component={[Input, { placeholder: '请输入地址' }]}
/>
<Field
name="remark"
title="备注"
decorator={[FormItem, {
labelWidth: 120,
labelAlign: 'left',
tooltip: '一段较长的说明文案,用于演示气泡提示',
tooltipLayout: 'icon',
}]}
component={[Input, { placeholder: '请输入备注' }]}
/>
</FormLayout>
<FormButtonGroup>
<Submit onSubmit={onSubmit}>提交</Submit>
</FormButtonGroup>
</FormProvider>
)
}长文本:省略与换行
标签默认单行显示,超出 labelWidth 时省略;长按带虚线的标签可查看全文。设置 labelWrap 后,标签在固定宽度内完整换行。wrapperWrap 用于控件区域的文本换行,下面通过相同的已选长地址对照两种模式:wrapperWrap={false} 保持单行,可左右滑动查看全文;wrapperWrap={true} 完整换行。另以阅读状态展示包含换行符和连续英文的内容。
import { FormButtonGroup, FormItem, FormLayout, Input, Picker, Submit } from '@silver-formily/antd-mobile'
import { createForm } from '@silver-formily/core'
import { Field, FormProvider } from '@silver-formily/react'
const addressOptions = [[{ label: '上海市浦东新区张江高科技园区祖冲之路 123 号研发中心 A 栋 1208 室', value: 'office' }]]
const form = createForm({
initialValues: {
scrollingAddress: ['office'],
wrappedAddress: ['office'],
instructions: '第一行:请核对收件信息。\n第二行:配送前会通过电话联系。\nOrderReferenceWithoutSpaces012345678901234567890123456789',
},
})
function onSubmit(values: unknown) {
return Prompts.alert(JSON.stringify(values, null, 2))
}
export default function FormItemLongText() {
return (
<FormProvider form={form}>
<FormLayout labelWidth={96}>
<Field
name="ellipsis"
title="这是一个超出标签列宽度的完整收件地址标题"
decorator={[FormItem, { help: '标签默认单行省略,长按带虚线的标签查看全文。' }]}
component={[Input, { placeholder: '请输入收件地址' }]}
/>
<Field
name="wrapped"
title="这是一个超出标签列宽度的完整收件地址标题"
decorator={[FormItem, { labelWrap: true, help: '同样的标签,开启 labelWrap 后完整换行。' }]}
component={[Input, { placeholder: '请输入详细地址' }]}
/>
<Field
name="scrollingAddress"
title="内容滚动"
dataSource={addressOptions}
decorator={[FormItem, { wrapperWrap: false, help: '关闭 wrapperWrap:已选地址保持单行,可左右滑动查看全文,点击可重新选择。' }]}
component={[Picker]}
/>
<Field
name="wrappedAddress"
title="已选换行"
dataSource={addressOptions}
decorator={[FormItem, { wrapperWrap: true, help: '相同的已选地址,开启 wrapperWrap 后完整换行。' }]}
component={[Picker]}
/>
<Field
name="instructions"
title="内容换行"
pattern="readPretty"
decorator={[FormItem, { wrapperWrap: true }]}
component={[Input, { placeholder: '配送说明' }]}
/>
</FormLayout>
<FormButtonGroup>
<Submit onSubmit={onSubmit}>提交</Submit>
</FormButtonGroup>
</FormProvider>
)
}禁用与只读
通过字段的 pattern="disabled" 禁用输入,表单项自动呈现禁用样式。pattern="readOnly" 保留输入框但不可编辑,pattern="readPretty" 则展示为纯文本。
import { FormButtonGroup, FormItem, FormLayout, Input, Submit } from '@silver-formily/antd-mobile'
import { createForm } from '@silver-formily/core'
import { Field, FormProvider } from '@silver-formily/react'
const form = createForm({
initialValues: {
disabled: '暂不可修改',
readOnly: '可选中复制,不可修改',
preview: '已保存的资料',
},
})
function onSubmit(values: unknown) {
return Prompts.alert(JSON.stringify(values, null, 2))
}
export default function FormItemStates() {
return (
<FormProvider form={form}>
<FormLayout labelWidth={80}>
<Field name="editable" title="正常输入" decorator={[FormItem]} component={[Input, { placeholder: '可以在此输入' }]} />
<Field
name="disabled"
title="禁用状态"
pattern="disabled"
decorator={[FormItem, { disabled: true, help: '字段与整行同时禁用。' }]}
component={[Input, { placeholder: '禁用时不可输入' }]}
/>
<Field
name="readOnly"
title="只读状态"
pattern="readOnly"
decorator={[FormItem]}
component={[Input, { placeholder: '只读内容' }]}
/>
<Field
name="preview"
title="阅读状态"
pattern="readPretty"
decorator={[FormItem]}
component={[Input, { placeholder: '阅读内容' }]}
/>
</FormLayout>
<FormButtonGroup>
<Submit onSubmit={onSubmit}>提交</Submit>
</FormButtonGroup>
</FormProvider>
)
}垂直布局
FormLayout layout="vertical" 为整组表单项设置上下布局;单个 FormItem 也能用 layout 覆盖。多行输入和较长的问题说明适合这一布局。
import { FormButtonGroup, FormItem, FormLayout, Input, Submit } from '@silver-formily/antd-mobile'
import { createForm } from '@silver-formily/core'
import { Field, FormProvider } from '@silver-formily/react'
const form = createForm()
function onSubmit(values: unknown) {
return Prompts.alert(JSON.stringify(values, null, 2))
}
export default function FormItemVertical() {
return (
<FormProvider form={form}>
<FormLayout layout="vertical">
<Field
name="name"
title="联系人"
required
decorator={[FormItem, { help: '标签位于输入框上方,提交时检查必填。' }]}
component={[Input, { placeholder: '请输入联系人姓名' }]}
/>
<Field
name="notes"
title="请填写本次配送需要注意的事项以及方便联系的时间段"
decorator={[FormItem, { labelWrap: true, tooltip: '例如:工作日晚上六点后联系。' }]}
component={[Input.TextArea, { placeholder: '请输入配送备注', rows: 3 }]}
/>
<Field
name="phone"
title="联系电话"
decorator={[FormItem, { layout: 'horizontal', labelWidth: 80, help: '这一项单独覆盖为横向布局。' }]}
component={[Input, { placeholder: '请输入联系电话' }]}
/>
</FormLayout>
<FormButtonGroup>
<Submit onSubmit={onSubmit}>提交</Submit>
</FormButtonGroup>
</FormProvider>
)
}提示说明
默认点击图标显示 tooltip,tooltipLayout="text" 改为长按标签文字约 500ms 后触发。短按标签仍聚焦输入框或打开选择器;长按结束不会触发控件。可以用 tooltipIcon 自定义提示图标。长说明和连续链接都会在手机视口内换行。
import { FormButtonGroup, FormItem, FormLayout, Input, Submit } from '@silver-formily/antd-mobile'
import { createForm } from '@silver-formily/core'
import { Field, FormProvider } from '@silver-formily/react'
const form = createForm()
function onSubmit(values: unknown) {
return Prompts.alert(JSON.stringify(values, null, 2))
}
export default function FormItemTooltip() {
return (
<FormProvider form={form}>
<FormLayout labelWidth={96}>
<Field
name="nickname"
title="图标提示"
decorator={[FormItem, { tooltip: '点击标签旁的图标查看说明;点击空白处关闭。' }]}
component={[Input, { placeholder: '请输入昵称' }]}
/>
<Field
name="account"
title="文字提示"
decorator={[FormItem, { tooltipLayout: 'text', tooltip: '长按带虚线的标签文字查看说明;短按仍聚焦输入框。' }]}
component={[Input, { placeholder: '请输入账号' }]}
/>
<Field
name="reference"
title="长说明"
decorator={[FormItem, {
tooltipIcon: <span>?</span>,
tooltip: '提示内容会根据手机屏幕宽度自动换行,较长的连续链接也不会撑出页面。参考链接:https://example.com/help/VeryLongReferenceWithoutSpaces012345678901234567890123456789',
}]}
component={[Input, { placeholder: '请输入参考编号' }]}
/>
</FormLayout>
<FormButtonGroup>
<Submit onSubmit={onSubmit}>提交</Submit>
</FormButtonGroup>
</FormProvider>
)
}外观与控件布局
bordered={false} 隐藏当前行顶部分隔线;wrapperWidth 与 wrapperAlign 配合控制输入区的宽度和位置。控件内部文字对齐通过控件自身属性设置。字段不设置标题时可隐藏标签而保留整行输入区域。
import { FormButtonGroup, FormItem, FormLayout, Input, Submit } from '@silver-formily/antd-mobile'
import { createForm } from '@silver-formily/core'
import { Field, FormProvider } from '@silver-formily/react'
const form = createForm()
function onSubmit(values: unknown) {
return Prompts.alert(JSON.stringify(values, null, 2))
}
export default function FormItemAppearance() {
return (
<FormProvider form={form}>
<FormLayout labelWidth={80}>
<Field name="default" title="默认分隔" decorator={[FormItem]} component={[Input, { placeholder: '请输入内容' }]} />
<Field
name="borderless"
title="无分隔线"
decorator={[FormItem, { bordered: false }]}
component={[Input, { placeholder: '这一行不显示顶部分隔线' }]}
/>
<Field
name="amount"
title="控件靠右"
decorator={[FormItem, { wrapperWidth: 120, wrapperAlign: 'right', extra: '元' }]}
component={[Input, { placeholder: '请输入金额', style: { '--text-align': 'right' } }]}
/>
<Field
name="search"
title="搜索内容"
decorator={[FormItem, { label: null, help: '隐藏标签后,输入区域占据整行。' }]}
component={[Input, { placeholder: '无标签输入框' }]}
/>
</FormLayout>
<FormButtonGroup>
<Submit onSubmit={onSubmit}>提交</Submit>
</FormButtonGroup>
</FormProvider>
)
}箭头与清除按钮
控件区内存在带 data-form-item-trigger 属性的入口时,自动显示右侧箭头,适用于 Picker、DatePicker、CascadePicker 及自定义控件。挂载后检测一次入口,不监听后续 DOM 变化;嵌套 FormItem 的入口只影响其自身。禁用态保留箭头,纯预览无入口时不自动显示。显式 arrow / arrowIcon 配置优先,例如 arrowIcon: false 可隐藏箭头。
设置 decorator={[FormItem, { clearable: true }]} 后,字段为空时显示箭头,有值时切换为清除按钮。点击清除会将字段值设为 undefined,并触发字段输入流程;不会触发行点击或打开选择器。禁用、只读和阅读态不显示清除按钮。
显式传入 arrowIcon 时优先使用自定义内容,包括 null 和 false。clearable 默认关闭。
清除时自动更新字段值,onClear 可用作清除后的通知。
API
属性
| 属性名 | 类型 | 描述 | 默认值 |
|---|---|---|---|
clearable | boolean | 自动切换箭头与清除按钮 | false |
onClear | () => void | 清除回调 | - |
labelStyle | CSSProperties | 标签样式 | - |
colon | boolean | 是否在标签后显示英文冒号,优先于 FormLayout 配置 | false |
labelAlign | enum | 标签文本对齐方式 | - |
labelWrap | boolean | 标签内容超长时是否换行 | false |
labelWidth | number | string | 标签宽度 | - |
wrapperWidth | number | string | 控件宽度 | - |
wrapperAlign | enum | 控件内容对齐方式 | - |
wrapperWrap | boolean | 控件内容超长时是否换行 | false |
wrapperStyle | CSSProperties | 控件样式 | - |
help | ReactNode | 帮助文案 | - |
asterisk | boolean | 是否显示星号,默认根据字段必填状态推导 | - |
tooltip | ReactNode | 问号提示内容 | - |
tooltipLayout | enum | 问号提示布局 | 'icon' |
tooltipIcon | ReactNode | 自定义问号图标 | - |
layout | enum | 布局模式 | - |
bordered | boolean | 是否显示边框 | - |
gridSpan | number | 栅格占位数(配合 FormGrid) | - |
继承 antd-mobile List.Item 中除 title、prefix、description 以外的配置项(这些区域由装饰器管理),请参考 List.Item 官方文档。
自动反馈按错误、告警顺序逐条展示;仅在二者均为空时展示成功反馈。校验进行中隐藏旧反馈,默认整体状态为 pending。反馈颜色使用 antd-mobile 的设计 token。