* feat: add scrollToFirstError support * add test case * clean up * coverage * feat: add scrollToFirstError support * add test case * clean up * coverage * update docs
14 KiB
category | subtitle | type | cols | title |
---|---|---|---|---|
Components | 表单 | 数据录入 | 1 | Form |
高性能表单控件,自带数据域管理。包含数据录入、校验以及对应样式。
何时使用
- 用于创建一个实体或收集信息。
- 需要对输入的数据类型进行校验时。
API
Form
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
component | 设置 Form 渲染元素,为 false 则不创建 DOM 节点 |
ComponentType | false | form |
colon | 配置 Form.Item 的 colon 的默认值。表示是否显示 label 后面的冒号 (只有在属性 layout 为 horizontal 时有效) |
boolean | true |
fields | 通过状态管理(如 redux)控制表单字段,如非强需求不推荐使用。查看示例 | FieldData[] | - |
form | 经 Form.useForm() 创建的 form 控制实例,不提供时会自动创建 |
FormInstance | - |
hideRequiredMark | 隐藏所有表单项的必选标记 | boolean | false |
initialValues | 表单默认值,只有初始化以及重置时生效 | object | - |
labelAlign | label 标签的文本对齐方式 | left | right |
right |
labelCol | label 标签布局,同 <Col> 组件,设置 span offset 值,如 {span: 3, offset: 12} 或 sm: {span: 3, offset: 12} |
object | - |
layout | 表单布局 | horizontal | vertical | inline |
horizontal |
name | 表单名称,会作为表单字段 id 前缀使用 |
string | - |
scrollToFirstError | 提交失败自动滚动到第一个错误字段 | false | - |
size | 设置字段组件的尺寸(仅限 antd 组件) | small | middle | large |
- |
validateMessages | 验证提示模板,说明见下 | ValidateMessages | - |
wrapperCol | 需要为输入控件设置布局样式时,使用该属性,用法同 labelCol | object | - |
onFinish | 提交表单且数据验证成功后回调事件 | Function(values) | - |
onFinishFailed | 提交表单且数据验证失败后回调事件 | Function({ values, errorFields, outOfDate }) | - |
onFieldsChange | 字段更新时触发回调事件 | Function(changedFields, allFields) | - |
onValuesChange | 字段值更新时触发回调事件 | Function(changedValues, allValues) | - |
validateMessages
Form 为验证提供了默认的错误提示信息,你可以通过配置 validateMessages
属性,修改对应的提示模板。一种常见的使用方式,是配置国际化提示信息:
const validateMessages = {
required: "'${name}' 是必选字段",
// ...
};
<Form validateMessages={validateMessages} />;
此外,ConfigProvider 也提供了全局化配置方案,允许统一配置错误提示模板:
const validateMessages = {
required: "'${name}' 是必选字段",
// ...
};
<ConfigProvider form={{ validateMessages }}>
<Form />
</ConfigProvider>;
Form.Item
表单字段组件,用于数据双向绑定、校验、布局等。
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
colon | 配合 label 属性使用,表示是否显示 label 后面的冒号 |
boolean | true |
dependencies | 设置依赖字段,说明见下 | NamePath[] | - |
extra | 额外的提示信息,和 help 类似,当需要错误信息和提示文案同时出现时,可以使用这个。 |
string|ReactNode | - |
getValueFromEvent | 设置如何将 event 的值转换成字段值 | (..args: any[]) => any | - |
hasFeedback | 配合 validateStatus 属性使用,展示校验状态图标,建议只配合 Input 组件使用 |
boolean | false |
help | 提示信息,如不设置,则会根据校验规则自动生成 | string|ReactNode | - |
htmlFor | 设置子元素 label htmlFor 属性 |
string | - |
noStyle | 为 true 时不带样式,作为纯字段控件使用 |
boolean | false |
label | label 标签的文本 |
string|ReactNode | - |
labelAlign | 标签文本对齐方式 | left | right |
right |
labelCol | label 标签布局,同 <Col> 组件,设置 span offset 值,如 {span: 3, offset: 12} 或 sm: {span: 3, offset: 12} 。你可以通过 Form 的 labelCol 进行统一设置。当和 Form 同时设置时,以 Item 为准 |
object | - |
name | 字段名,支持数组 | NamePath | - |
normalize | 转换字段值给控件 | (value, prevValue, prevValues) => any | - |
required | 是否必填,如不设置,则会根据校验规则自动生成 | boolean | false |
rules | 校验规则,设置字段的校验逻辑。点击此处查看示例 | Rule[] | - |
shouldUpdate | 自定义字段更新逻辑,说明见下 | boolean | (prevValue, curValue) => boolean | false |
trigger | 设置收集字段值变更的时机 | string | onChange |
validateFirst | 当某一规则校验不通过时,是否停止剩下的规则的校验 | boolean | false |
validateStatus | 校验状态,如不设置,则会根据校验规则自动生成,可选:'success' 'warning' 'error' 'validating' | string | - |
validateTrigger | 设置字段校验的时机 | string | string[] | onChange |
valuePropName | 子节点的值的属性,如 Switch 的是 'checked' | string | 'value' |
wrapperCol | 需要为输入控件设置布局样式时,使用该属性,用法同 labelCol 。你可以通过 Form 的 wrapperCol 进行统一设置。当和 Form 同时设置时,以 Item 为准。 |
object | - |
dependencies
当字段间存在依赖关系时使用。如果一个字段设置了 dependencies
属性。那么它所依赖的字段更新时,该字段将自动触发更新与校验。一种常见的场景,就是注册用户表单的“密码”与“确认密码”字段。“确认密码”校验依赖于“密码”字段,设置 dependencies
后,“密码”字段更新会重新触发“校验密码”的校验逻辑。你可以参考具体例子。
shouldUpdate
Form 通过增量更新方式,只更新被修改的字段相关组件以达到性能优化目的。大部分场景下,你只需要编写代码或者与 dependencies
属性配合校验即可。而在某些特定场景,例如修改某个字段值后出现新的字段选项、或者纯粹希望表单任意变化都对某一个区域进行渲染。你可以通过 shouldUpdate
修改 Form.Item 的更新逻辑。
当 shouldUpdate
为 true
时,Form 的任意变化都会使该 Form.Item 重新渲染。这对于自定义渲染一些区域十分有帮助:
<Form.Item shouldUpdate>
{() => {
return <pre>{JSON.stringify(form.getFieldsValue(), null, 2)}</pre>;
}}
</Form.Item>
你可以参考示例查看具体使用场景。
当 shouldUpdate
为方法时,表单的每次数值更新都会调用该方法,提供原先的值与当前的值以供你比较是否需要更新。这对于是否根据值来渲染额外字段十分有帮助:
<Form.Item shouldUpdate={(prevValues, curValues) => prevValues.additional !== curValues.additional}>
{() => {
return (
<Form.Item name="other">
<Input />
</Form.Item>
);
}}
</Form.Item>
你可以参考示例查看具体使用场景。
Form.List
为字段提供数组化管理。
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
name | 字段名,支持数组 | NamePath | - |
children | 渲染函数 | (fields: Field[], operation: { add, remove, move }) => React.ReactNode | - |
<Form.List>
{fields => (
<div>
{fields.map(field => (
<Form.Item {...field}>
<Input />
</Form.Item>
))}
</div>
)}
</Form.List>
Form.Provider
提供表单间联动功能,其下设置 name
的 Form 更新时,会自动触发对应事件。查看示例。
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
onFormChange | 子表单字段更新时触发 | Function(formName: string, info: { changedFields, forms }) | - |
onFormFinish | 子表单提交时触发 | Function(formName: string, info: { values, forms }) | - |
<Form.Provider
onFormFinish={name => {
if (name === 'form1') {
// Do something...
}
}}
>
<Form name="form1">...</Form>
<Form name="form2">...</Form>
</Form.Provider>
FormInstance
名称 | 说明 | 类型 |
---|---|---|
getFieldValue | 获取对应字段名的值 | (name: NamePath) => any |
getFieldsValue | 获取一组字段名对应的值,会按照对应结构返回 | (nameList?: NamePath[], filterFunc?: (meta: { touched: boolean, validating: boolean }) => boolean) => any |
getFieldError | 获取对应字段名的错误信息 | (name: NamePath) => string[] |
getFieldsError | 获取一组字段名对应的错误信息,返回为数组形式 | (nameList?: NamePath[]) => FieldError[] |
isFieldTouched | 检查对应字段是否被用户操作过 | (name: NamePath) => boolean |
isFieldsTouched | 检查一组字段是否被用户操作过,allTouched 为 true 时检查是否所有字段都被操作过 |
(nameList?: NamePath[], allTouched?: boolean) => boolean |
isFieldValidating | 检查一组字段是否正在校验 | (name: NamePath) => boolean |
resetFields | 重置一组字段到 initialValues |
(fields?: NamePath[]) => void |
scrollToField | 滚动到对应字段位置 | (name: NamePath, options: [ScrollOptions]) => void |
setFields | 设置一组字段状态 | (fields: FieldData[]) => void |
setFieldsValue | 设置表单的值 | (values) => void |
submit | 提交表单,与点击 submit 按钮效果相同 |
() => void |
validateFields | 触发表单验证 | (nameList?: NamePath[]) => Promise |
validateFields 返回示例
validateFields()
.then(values => {
/*
values:
{
username: 'username',
password: 'password',
}
*/
})
.catch(errorInfo => {
/*
errorInfo:
{
values: {
username: 'username',
password: 'password',
},
errorFields: [
{ password: ['username'], errors: ['Please input your Password!'] },
],
outOfDate: false,
}
*/
});
Interface
NamePath
string | number | (string | number)[]
FieldData
名称 | 说明 | 类型 |
---|---|---|
touched | 是否被用户操作过 | boolean |
validating | 是否正在校验 | boolean |
errors | 错误信息 | string[] |
name | 字段名称 | NamePath[] |
value | 字段对应值 | any |
Rule
Rule 支持接收 object 进行配置,也支持 function 来动态获取 from 的数据:
type Rule = RuleConfig | ((form: FormInstance) => RuleConfig);
名称 | 说明 | 类型 |
---|---|---|
enum | 是否匹配枚举中的值 | any[] |
len | string 类型时为字符串长度;number 类型时为确定数字; array 类型时为数组长度 | number |
max | string 类型为字符串最大长度;number 类型时为最大值;array 类型时为数组最大长度 | number |
message | 错误信息,不设置时会通过模板自动生成 | string |
min | string 类型为字符串最小长度;number 类型时为最小值;array 类型时为数组最小长度 | number |
pattern | 正则表达式匹配 | RegExp |
required | 是否为必选字段 | boolean |
transform | 将字段值转换成目标值后进行校验 | (value) => any |
type | 类型,常见有 string |number |boolean |url | email 。更多请参考此处 |
string |
validator | 自定义校验,接收 Promise 作为返回值。示例参考 | (rule, value) => Promise |
whitespace | 如果字段仅包含空格则校验不通过 | boolean |
validateTrigger | 设置触发验证时机,必须是 Form.Item 的 validateTrigger 的子集 |
string | string[] |
从 v3 升级到 v4
如果你是 antd v3 的用户,你可以参考迁移示例。
FAQ
自定义 validator 没有效果
这是由于你的 validator
有错误导致 callback
没有执行到。你可以选择通过 async
返回一个 promise 或者使用 try...catch
进行错误捕获:
validator: async (rule, value) => {
throw new Error('Something wrong!');
}
// or
validator(rule, value, callback) => {
try {
throw new Error('Something wrong!');
} catch (err) {
callback(err);
}
}
为何在 Modal 中调用 form 控制台会报错?
Warning: Instance created by
useForm
is not connect to any Form element. Forget to passform
prop?
这是因为你在调用 form 方法时,Modal 还未初始化导致 form 没有关联任何 Form 组件。你可以通过给 Modal 设置 forceRender
将其预渲染。示例点击此处。