输入类 · Form
表单

表单(Form)

  • 按需重绘,避免了不必要的全量渲染, 性能更高
  • 简单易用,结构极简,避免了不必要的层级嵌套
  • 完善的无障碍支持
  • 在 Form 外部可方便地获取 formState / fieldState
    提供在外部对表单内部进行操作的方法:formApi / fieldApi
  • 支持将自定义组件封装成表单控件,你可以通过 Form 提供的扩展机制(withField HOC)快捷接入自己团队的组件
  • 支持 Form level / Field level 级别的赋值、校验(同步/异步)

表单控件(Field)

Semi 将所有自带的输入控件(文本输入框、下拉选择、复选框、单选框等)都使用 withField 封装了一次。 接管了他们的数据流(value & onChange)
使用的时候,需要从 Form 中导出(注意:从 Form 导出的控件才具有数据同步功能)

目前 Form 提供了如下表单控件

  • InputInputNumberTextAreaSelectCheckboxRadioRadioGroupSwitchDatePickerTimePickerSliderInputGroupTreeSelectCascaderRatingAutoCompleteUploadLabelErrorMessageSectionTagInput 都挂载在 Form 下,使用时直接以<Form.Input> 、<Form.Select>声明即可
Form 提供的 Field 级别组件,它的 value(或者 valueKey 指定的其他属性)、onChange(或 onKeyChangeFnName 指定的其他回调函数) 属性都会被 Form 劫持,所以
注意事项
1. 你不需要也不应该用 onChange 来作同步,当然你可以继续监听 onChange 事件获取最新的值
2. 你不能再用控件的`value`、`defaultValue`、`checked`、`defaultChecked`等属性来设置表单控件的值,默认值可以通过 Field 的`initValue`或者 Form 的`initValues`设置
3. 你不应该直接修改 FormState 的值,所有对 Form 内数据的修改都应该通过提供的formApi、fieldApi来完成

代码演示

声明表单的多种写法

Semi Form 同时支持多种写法

基本写法

从 Form 中导出表单控件,给表单控件添加field属性,将其放置于 Form 内部即可
还可以给每个表单控件设置label属性,不传入时默认与 field 相同
label可以直接传入字符串,亦可以以 object 方式声明,配置 extrarequiredoptional等属性应对更复杂的场景
注意事项
对于Field级别组件来说,field 属性是必填项!

支持的其他写法

当你需要在 Form 结构内部直接获取到 formStateformApivalues 等值时,你还可以使用以下的写法
注意事项
注意,此处获取的 formState、values 等并没有经过 deepClone。你应该只做读操作,而不应该做写操作,否则会导致你可能意外修改了form内部的状态。所有对 Form 内部状态的更新都应该通过 formApi 去操作

通过 render 属性传入

即 render props

通过 child render function

Form 的 children 是一个 function,return 出所有表单控件

通过 props.component

通过 component 属性直接将整个内部结构以 ReactNode 形式传入

已支持的表单控件

表单控件值的绑定

每个表单控件都需要以field属性绑定一个字段名称,用于将表单项的值正确映射到FormState values / errors / touched 中
字段可以是简单的字符串,可以是包含.或者[]的字符串, 支持多级嵌套
下面是字段名称以及他们在 FormState 中的映射路径的示例
FieldResolution
usernameformState.values.username
user[0]formState.values.user[0]
siblings.1formState.values.siblings[1]
siblings['2']formState.values.siblings[2]
parents[0].nameformState.values.parents[0].name
parents[1]['name']formState.values.parents[1].name

表单布局

  • 垂直布局:表单控件之间上下垂直排列(默认)
    Semi Design 更推荐表单采用垂直布局
  • 水平布局:表单控件之间水平排列 你可以通过设置 layout='horizontal'来使用水平布局
  • labelPosition、labelAlign
    你可以通过设置 labelPosition、labelAlign 控制 label 在 Field 中出现的位置,文本对齐的方向
  • 更复杂的布局 你还可以结合 Grid 提供的 Row、Col,来对表单进行你想要的排列

表单分组

字段数量较多的表单应考虑对字段进行分组,可以使用Form.Section对 Fields 进行分组(仅影响布局,不会影响数据结构)

wrapperCol / labelCol

需要为 Form 内的所有 Field 设置统一的布局时,可以在 Form 上设置 wrapperCol 、labelCol 快速生成布局,无需手动使用 Row、Col 手动布局
wrapperCollabelCol属性配置参考Col 组件

隐藏Label

Form 会自动为 Field 控件插入 Label。如果你不需要自动插入 Label 模块, 可以通过在 Field 中设置noLabel=true将自动插入 Label 功能关闭(此时 Field 仍然具备自动展示 ErrorMessage 的能力,因此 DOM 结构与原始控件依然会有区别)
如果你希望与原始控件保持 DOM 结构一致,可以使用 pure=true,此时除了数据流被接管外,DOM结构不会有任何变化(你需要自行负责 ErrorMessage的渲染,同时它也无法被 formProps.wrapperCol 属性影响)

内嵌 Label

通过将 labelPosition 设为inset,可以将 Label 内嵌在表单控件中。目前支持这项功能的组件有InputInputNumberDatePickerTimePickerSelectTreeSelectCascaderTagInput

导出 Label、ErrorMessage 使用

如果你需要 Form.Label、Form.ErrorMessage 模块自行组合使用,可以从 Form 中导出
例如:当自带的 Label、ErrorMessage 布局不满足业务需求,需要自行组合位置,但又希望能直接使用 Label、ErrorMessage 的默认样式时

使用 Form.Slot 放置自定义组件

当你的自定义组件,需要与 Field 组件保持同样的布局样式时,你可以通过 Form.Slot 放置你的自定义组件
在 Form 组件上设置的 labelWidthlabelAlignwrapperCollabelCol 会自动作用在 Form.Slot 上
Slot 属性配置详见Form.Slot

使用 helpText、extraText 放置提示信息

可以通过helpText放置自定义提示信息,与校验信息(error)公用同一区块展示,两者均有值时,优先展示校验信息。
可以通过extraText放置额外的提示信息,当需要错误信息和提示文案同时出现时,可以使用这个配置,常显,位于 helpText/error 后
当传入 validateStatus 时,优先展示 validateStatus 值对应的 UI 样式。不传入时,以 field 内部校验状态为准。
通过配置 extraTextPosition,你可以控制 extraText 的显示位置。可选值 bottommiddle
例如如当你希望将 extraText 提示信息显示在 Label 与 Field 控件中间时
该属性可在 Form 上统一配置,亦可在每个 Field 上单独配置,同时传入时,以 Field 的配置为准。

使用 InputGroup 组合多个 Field

当你需要将一些表单控件组合起来使用时,你可以用Form.InputGroup将其包裹起来
当你给SelectInput等表单控件加上 field 属性时,Form会默认给每个 Field 控件自动插入Label
而在InputGroup中一般仅需要一个属于整个 Group 的 Label,你可以在 InputGroup 中设置 label 属性,插入一个属于 Group 的Label
label可配置属性详见Label
你可以将 Form 放置于 Modal 中,以弹窗形式承载
在提交时,通过 formApi.validate()对 Field 进行集中校验

配置初始值与校验规则

  • 你可以通过rules为每个 Field 表单控件配置校验规则
    Form 内部的校验库基于 async-validator,更多配置规则可查阅其官方文档
  • 你可以通过 form 的initValues为整个表单统一设置初始值,也可以在每个 field 中通过initValue设置初始值(后者优先级更高)
  • 可以通过 trigger 为每个 Field 配置不同的校验触发时机,默认为 change(即onChange触发时,自动进行校验)。还支持 change、blur、mount、custom 或以上的组合。v2.42 后支持通过 FormProps 统一配置, 若都配置时,以 FieldProps 为准
  • 可以通过 stopValidateWithError 开关,决定使用 rules 校验时,当碰到第一个检验不通过的 rules 后,是否继续触发后续 rules 的校验。v2.42 后支持通过 FormProps 统一配置,若都配置时,以 FieldProps 为准

自定义校验(Form 级别)

你可以给Form整体设置自定义校验函数 validateFields。submit 或调用formApi.validate()时会进行调用
注意
当配置了 Form级别校验器 validateFields 后,Field 级别的校验器(fieldProps.validate、fieldProps.rules 将不再生效)

同步校验

校验通过时,你应该返回一个空字符串;
校验失败时,你应该返回错误信息(Object,key 为 fieldName,value 为对应的错误信息)

异步校验

异步校验时,你应当返回一个 promise,在 promise.then()中 你需要 return 对应的错误信息

自定义校验(Field 级别)

你可以指定单个表单控件的自定义校验函数,支持同步、异步校验(通过返回 promise)

手动触发指定 Field 校验

当你希望手动触发某些特定 Field 的校验操作时,可以通过 formApi.validate 完成。不传入参数时,默认对全部 Field 进行校验,传入参数时,以参数指定为准

表单联动

你可以通过监听 Field 的 onChange 事件,然后使用 formApi 进行相关修改,来使 Field 之间达到联动

动态表单

动态删减表单项

使用 ArrayField

针对动态增删的数组类表单项,我们提供了 ArrayField 作用域来简化 add/remove 的操作
ArrayField 自带了 add、remove、addWithInitValue 等 api 用来执行新增行,删除行,新增带有初始值的行等操作
ArrayField 详细的 API请查阅下方 ArrayField Props 注意:ArrayField 的 initValue 类型必须是数组

嵌套 ArrayField

ArrayField 支持多级嵌套,如下是一个两级嵌套的例子

Hooks 的使用

我们提供了四个 Hooks,使你在不需要通过 props 传递的情况下,也能在放置于 Form 结构内部的 Functional Component 中也能轻易访问到 Form 内部状态数据,以及调用 Form、Field 的相关 api

useFormApi

useFormApi 允许你通过 hook,在 Functional Component 内直接访问父级 Form 组件的 formApi

useFormState

useFormState 允许你通过 hook,在 Functional Component 内直接访问父级 Form 组件的 formState

useFieldApi

useFieldApi 允许你通过 hook,在 Functional Component 内直接调用指定 Field 的 api

useFieldState

useFieldState 允许你通过 hook,在 Functional Component 内直接访问指定 Field 的 State

HOC 的使用

我们提供了两个 HOC: withFormApiwithFormState,可以在其他组件内部访问到 Form 的 formApi 以及内部状态 formState 提供了 HOC: withField,用于将自定义组件封装成符合 Semi Form 数据流的表单控件

HOC-withFormApi

你可以通过 withFormApi HOC 来封装组件,使得该组件内部可以直接调用父级 Form 组件的 formApi
注意封装后的组件必须放置于 Form 结构内部

HOC-withFormState

你可以通过 withFormState HOC 来封装组件,使得该组件内部可直接访问到父级 Form 组件的 FormState
注意封装后的组件必须放置于 Form 结构内部 (因其强依赖 Context 机制进行消费)

withField 封装自定义表单控件

通过 withField,你可以将其他自定义组件扩展成为表单控件,由 Form 接管其行为
注意
自定义组件必须为受控组件,只有受控组件,才能被 Form 接管,正确地进行值的更新
withField 主要做了以下事情
  • 负责接管组件的 value(或者 valueKey 指定的其他属性)、onChange(或 onKeyChangeFnName 指定的其他回调函数)
  • 负责在表单控件上方插入 Field 的<Form.Label>
  • 负责在表单控件下方插入 Field 的<ErrorMessage>
  • 负责在表单控件下方插入 Field 的 extraText
withFieldOption 具体配置可参考 withField Option
你的自定义受控组件需要做以下事情:
  • 值发生变化时,调用props.onChange (或 onKeyChangeFnName 指定的其他回调函数) 并且将最新的值作为入参
  • 响应props.value(或者 valueKey 指定的其他属性)的变化,并更新你的组件UI渲染结果

API 参考

Form Props

属性说明类型默认值
autoScrollToError若为 true,submit 或者调用 formApi.validate()校验失败时,将会自动滚动至出错的字段。object 型配置参考optionsboolean| objectfalse
allowEmpty是否保留values中为空值的field的key,true时保留key,false时移除keybooleanfalse
classNameform 标签的 classnamestring
component用于声明表单控件,不可与 render、props.children 同时使用ReactNode
disabled统一应用在每个 Field 的 disabled 属性booleanfalse
extraTextPosition统一应用在每个 Field 上的extraTextPosition属性,控制extraText的显示位置,可选middle(垂直方向以Label、extraText、Field主体的顺序显示)、bottom (垂直方向以Label、Field主体、extraText的顺序显示)string'bottom'
getFormApiform mounted 时会回调该函数,将 formAPI 作为参数传入。formApi 可用于修改 form 内部状态(值、校验状态、错误信息)function(formApi:object)
initValues用于统一设置表单初始值(仅会在组件挂载时消费一次),例如{fieldA:'hello', fieldB:['arr1', 'arr2']}object
layoutForm 表单控件间的布局,目前支持水平(horizontal)、垂直(vertical)两种string'vertical'
labelAlign统一配置label 的 text-align 值string'left'
labelCol统一应用在每个 Field 的 label 标签布局,同Col 组件,设置spanoffset值,如{span: 6, offset: 2}object
labelPosition统一配置Field 中 label 的位置,可选'top'、'left'、'inset'(inset 标签内嵌仅部分组件支持)string'top'
labelWidth统一配置label 宽度string|number
onChangeform 更新时触发,包括表单控件挂载/卸载/值变更/blur/验证状态变更/错误提示变更, 入参为 formStatefunction(formState:object)
onValueChangeform 的值被更新时触发,仅在表单控件值发生变化时触发。第一个入参为 formState.values,第二个入参为当前发生变化的 fieldfunction(values:object, changedValue: object)
onErrorChangeform 的校验状态被更新时触发。第一个入参为 formState.errors,第二个入参为当前发生变化的 field 的名称与校验结果(v2.66后提供)function(values:object, changedError: object)
onReset点击 reset 按钮或调用 formApi.reset()时的回调函数function()
onSubmit点击 submit 按钮或调用 formApi.submitForm(),数据验证成功后的回调函数function(values:object, e: event)
onSubmitFail点击 submit 按钮或调用 formApi.submitForm(),数据验证失败后的回调函数function(errors:object, values:object, e: event)
render用于声明表单控件,不可与 component、props.children 同时使用function
showValidateIconField 内的校验信息区块否自动添加对应状态的 icon 展示booleantrue
style可将内联样式传入 form 标签object
stopValidateWithError统一应用在每个 Field 的 stopValidateWithError,使用说明见 Field props中同名 API (v2.42后提供)booleanfalse
stopPropagation是否阻止 submit或reset事件冒泡,用于嵌套 Form 场景下,内部 Form submit或reset时阻止事件往外传播,触发外部Form的事件。默认为 { reset: false, submit: false }(v2.63后提供)object
trigger统一应用在每个 Field 的 trigger,使用说明详见 Field props中同名 API(v2.42后提供)string|array'change'
validateFieldsForm 级别的自定义校验函数,submit 时或 formApi.validate 时会被调用(配置Form级别校验器后,Field级别校验器在submit或formApi.validate()时不会再被触发)。支持同步校验、异步校验function(values)
wrapperCol统一应用在每个 Field 上的布局,同Col 组件,设置spanoffset值,如{span: 20, offset: 4}object

FormState

FormState 存储了所有 Form 内部的状态值,包括各表单控件的值,错误信息、touched 状态
进行表单提交时,实际提交的就是 formState.values
Name说明初始值示例
values表单的值{}{ fieldA: 'str', fieldB: true }
errors表单错误信息集合,你可以通过判断是否有错误信息来决定是否允许用户提交{}{ fieldA: 'length not valid'}
touched用户点击过的 field 集合{}{ fieldA: true }

如何访问 formState

FormApi

我们提供了 FormApi。你在 Form 内部、外部都可以很方便地获取到 formApi,它允许你使用 getter 和 setter 来获取和操作 formState 的值。
下面的表格描述了 formApi 中可用的功能。
关于作用域隔离
为了防止用户在读取 formState、values 等内部状态后,意外操作直接了修改 Form 组件的内部状态等情况,Semi 对于 formApi.setValue、setValues的入参、formApi.getFormState、getValue、getValues的返回结果都会自动进行 deepClone
Function说明example
getFormProps获取 Form 组件上当前所有props的值,例如可用于读取 disabled 等。v 2.57.0 后提供formApi.getFormProps(propNames?: string[])
getFormState获取 FormStateformApi.getFormState()
submitForm可手动触发 submit 提交操作formApi.submitForm()
reset可手动对 form 进行重置formApi.reset(fields?: Array <string>)
validate可手动触发对表单的校验,不传参时默认触发整全体Field的校验(配置Form级别校验器后,Field级别校验器在submit或formApi.validate()时不会再被触发),若想触发部分field的校验,将目标field数组传入即可formApi.validate()
.then(values=>{})
.catch(errors=>{})
或 formApi.validate(['fieldA','fieldB'])
setValues设置整个表单的值。第二个参数中的 isOverride 默认为 false
默认情况下只会从newValues中取 Form 中已存在的 field 的值更新到formState.values中。
当 isOverride 为true时,会直接以 newValues 覆盖赋值给 formState.values
formApi.setValues(newValues: object, { isOverride: boolean })
setValue提供直接修改 formState.values 方法,与 setValues 的区别是它仅修改单个 fieldformApi.setValue(field: string, newFieldValue: any)
getValue获取 单个 Field 的值formApi.getValue()
formApi.getValue(field: string)
getValues获取 所有 Field 的值formApi.getValues()
setTouched修改 formState.touchedformApi.setTouched(field: string, isTouched: boolean)
getTouched获取 Field 的 touched 状态formApi.getTouched(field: string)
setError修改 某个 field 的 error 信息formApi.setError(field: string, fieldErrorMessage: string)
getError获取 Field 的 error 状态formApi.getError(field: string)
getFieldExist获取 Form 中是否存在对应的 fieldformApi.getFieldExist(field: string)
scrollToField滚动至指定的 field, 第二个入参将透传至scroll-into-view-if-neededformApi.scrollToField(field: string, scrollOpts: ScrollIntoViewOptions)
scrollToError滚动至校验错误的field,可传指定 field 或者 index,传入 index 则滚动到第 index 个错误的 DOM,若不传参则滚动到DOM树中第一个校验出错的位置。 v2.61.0后提供formApi.scrollToError(
ScrollToErrorOptions
)

如何获取 formApi

  • Form 组件在 ComponentDidMount 阶段,会执行 props 传入的 getFormApi 回调,你可以在回调函数中保存 formApi 的引用,以便后续进行调用(示例如下代码)
    除此之外,我们还提供了其他方式获取 formApi,你可以根据喜好选择不同的调用方式
  • 通过 ref 的方式获取 Form 组件实例,直接访问实例上的 formApi
  • 通过 child render function 方式声明表单,formApi 会作为参数注入
  • 通过 render props 方式声明表单,formApi 会作为参数注入
  • 通过 useFormApi hook
  • 通过 withFormApi HOC

Field Props

关于Field ref
v1.30.0之前的版本,Field组件并不会做ref转发
v1.30后可直接通过ref获取底层控件实例,例如给Form.Input、Form.Select指定ref,直接获取到底层原始Input、Select组件的ref引用
属性说明类型默认值
convertfield 值改变后,在 rerender 前,对 filed 的值进行二次更新
使用示例: (value) => newValue
function(fieldValue)
field该表单控件的值在 formState.values 中的映射路径,Form 会使用该值来区分内部的表单控件
必填!!! 示例:Bindding Syntax
string
label该表单控件的 label 标签文本,不传的时候默认与 field 同名, 传入 object 时会将其透传给 Form.Label,具体配置请参考Labelstring|object
labelPosition该表单控件的 label 位置,可选'top'/'left'/'inset'。在Form与Field上同时传入时,以Field props为准string
labelAlign该表单控件的 label 文本的 text-align。在Form与Field上同时传入时,以Field props为准string
labelWidth该表单控件的 label 文本的 width。在Form与Field上同时传入时,以Field props为准string|number
noLabel当你不需要自动添加 label 时,可以将该值置为 trueboolean
noErrorMessage当你不需要自动添加 ErrorMessage 模块时,可以将该值置为 true,注意此时 helpText 也不会被展示boolean
name控件名称,传入时会自动在对应 field wrapper div 追加对应的 className,如:abc => '.semi-form-field-abc'。 v2.24 后,还会将 name 透传至底层组件消费,例如你可以用于配置 input的name属性string
fieldClassName整个 fieldWrapper 的 className,作用与 name 参数一致,区别是不会自动追加前缀string
fieldStyle整个 fieldWrapper 的 内联样式
v1.15.0开始提供
object
initValue该表单控件的初始值(仅在 Field mounted 时消费一次,后续更新无效),相比 Form 的 initValues 中的值,它的优先级更高any(类型取决于当前组件,详细见各组件的 api)
validate该表单控件的的自定义校验函数。支持同步、异步校验(通过返回promise)。
设置了 validate 时,rules 不会生效
使用示例:(fieldValue, values) => fieldValue >= 5 ? 'value not valid': ''
function(fieldValue, values)
rules校验规则,校验库基于async-validator
使用示例:const rules=[{ required: true, message: 'can't be null ' },
{ max: 10, message: 'can't more than 10 word' }]
array
validateStatus该表单控件的校验结果状态(仅影响样式),可选值:success/error/warning/defaultstring'default'
trigger触发校验的时机,可选值:blur/change/custom/mount,或以上值的组合['blur','change']
1、设置为 custom 时,仅会由 formApi/fieldApi 触发校验时被触发
2、mount(挂载时即触发一次校验)
string/array'change'
onChange值变化时触发的回调function(filedValue: any | ev: { target: { value: any }})
(具体参见各组件的 onChange 方法)
onBlur失去焦点时触发的回调function() (具体参见各组件的 onBlur 方法)
transform校验前转换字段值,转换后的值仅会在校验时被消费,对 formState 无影响
使用示例: (value) => Number
function(fieldValue)
allowEmptyString是否允许值为空字符串。默认情况下值为''时,该 field 对应的 key 会从 values 中移除,如果你希望保留该 key,那么需要将 allowEmptyString 设为 truebooleanfalse
stopValidateWithError为 true 时,使用 rules 校验,碰到第一个检验不通过的 rules 后,将不再触发后续 rules 的校验booleanfalse
helpText自定义提示信息,与校验信息公用同一区块展示,两者均有值时,优先展示校验信息ReactNode
extraText额外的提示信息,当需要错误信息和提示文案同时出现时,可以使用这个,位于 helpText/errorMessage 后ReactNode
pure是否仅接管数据流,为 true 时不会自动插入 ErrorMessage、Label、extraText 等模块,样式、DOM 结构与原始的组件保持一致booleanfalse
extraTextPosition控制extraText的显示位置,可选middle(垂直方向以Label、extraText、Field主体的顺序显示)、bottom (垂直方向以Label、Field主体、extraText的顺序显示);在Form与Field上同时传入时,以Field props为准string'bottom'
...other组件的其他可配置属性,与上面的属性平级一并传入即可,例如 Input 的 size/placeholder,Field 会将其透传至组件本身

ArrayField Props

针对动态增删的数组类表单项,我们提供了 ArrayField 作用域来简化 add/remove 的操作
属性说明类型默认值
field该表单控件的值在 formState.values 中的映射路径
必填,例如存在 ArrayField负责 a[0].name、a[1].name、a[2].name三行渲染,他们的父级为a,此处props.field应为 a
string
initValueArrayField的初始值,如果同时在 formProps.initValues 与 arrayFieldProps.initValue 中都配置了初始值,后者优先级更高Array[]
childrenArrayField的内容,类型为 Function,函数入参为 add、addWithInitValue 等操作函数 及 arrayFields,执行后应当返回 ReactNodeFunction(ArrayFieldChildrenProps) => ReactNode

Form.Section

属性说明类型版本
text段落标题ReactNodev1.0.0
className样式类名stringv1.0.0
style内联样式objectv1.0.0
children段落内容ReactNodev1.0.0

Form.Label

默认情况下,Label 会由 Form 自行插入到每个 Field 中。如果你需要在其他地方自行插入 Label,我们提供了 Label 组件可以导出
属性说明类型默认值版本
textLabel 内容ReactNode
required是否展示必填的*booleanfalse
extra跟随在 required 后的内容ReactNodev0.33.0
aligntext-alignstring'left'
className样式类名string
style内联样式string
widthlabel 宽度number/string
optional是否自动在text后追加"(可选)"文字标识(根据Locale配置的不同语言自动切换相同语义文本)。当该项为true时,required的*号将不再展示。若当表单项多数均为必填时,仅强调可选项会更使得整体视觉更简洁booleanfalsev2.18.0

Form.InputGroup

属性说明类型默认值版本
className样式类名string
style内联样式object
labelInputGroup 的 label 标签文本Label | string
labelPosition该表单控件的 label 位置,可选'top'/'left'/'inset'。在 Form 与 InputGroup 同时传入时,以 InputGroup props为准string'top'
extraText额外的提示信息,当需要错误信息和提示文案同时出现时,可以使用这个,位于 errorMessage 后ReactNodev2.29.0
extraTextPosition控制extraText的显示位置,可选middle(垂直方向以Label、extraText、Group的顺序显示)、bottom (垂直方向以Label、Group、extraText的顺序显示)string'bottom'v2.29.0
当 extraTextPositon 为 middle,且 labelPosition 为 left时。由于 extraText允许为 ReactNode,内容高度不定,Label将不再确保能与 Field / InputGroup 中的首行文本对齐。

Form.Slot

属性说明类型
labelslot 的Label 配置, 例如{ text: 'semi', align: 'left' };也可以直接传入 string,Slot 内部会自动封装成合法 Label 格式object|string
labelPositionslot 的 label 位置,默认情况下继承自 Form props,也可单独覆盖。可选'top'、'left'string
classNameslot 样式类名string
styleslot 内联样式object
childrenslot 的主体内容ReactNode
errorslot 的错误提示信息ErrorMessage|ReactNode

Form.ErrorMessage

  • 当 error 为 ReactNode、String、Boolean 时,直接渲染
  • 当 error 为数组时,会自动执行 join 操作聚合数组内的错误信息
属性说明类型
error错误信息内容string|array|ReactNode|boolean
className样式类名string
style内联样式object
showValidateIcon是否自动加上 validateStatus 对应的 iconboolean
validateStatus信息所属的校验状态,可选 default/error/warning/success(success一般建议与default样式相同)string

withFieldOption

key描述默认值
valueKey组件表示值的属性,如 Switch、Radio 的是'checked',Input 的是'value''value'
onKeyChangeFnName组件值变化时的回调函数,一般为'onChange''onChange'
valuePath值属性在回调函数中第一个参数的路径,如 Radio 的 onChange(e.target.checked),那么该值需要设为 target.checkd;RadioGroup 的 onChange(e.target.value),该值为'target.value';若第一个参数就是值本身,无需再往下取值,该项不需要设

Accessibility

ARIA

  • aria-labelledby、for
    • Field 组件,会自动添加 label DOM。label 的 for 属性与 props.idprops.nameprops.field 相同 ;label 的id 属性由 props.idprops.nameprops.field 决定,值格式为 ${props.field}-label;
    • 当 Form 或者 Field 的 props.labelPosition 设置为 inset时,此时不存在 label 标签,而是 div 标签。insetLabel 对应的 div 标签会被自动追加 id,值与上述 label 的 id 相同,对应 Field 组件的 aria-labelledby
    • Field 组件会被自动追加 aria-labelledby,值与上述 label 的id 相同
  • aria-required
    • 当 Field 配置了必填时(即 props.rules中包含 require: true 或 props.label配置了required: true),Field 组件会被自动追加 aria-required = true(Form.Switch、Form.CheckboxGroup 除外)
  • aria-invalidaria-errormessage
    • 当 Field 校验未通过时,Field 组件会被自动添加 aria-invalid = true 属性,Form.CheckboxGroup 除外。
    • 当 Field 校验未通过时,Field 组件会被自动追加 aria-errormessage 属性,值为 errorMessage 所对应DOM元素的 id (格式: ${props.field}-errormessage),Form.CheckboxGroup 除外。
  • aria-describedby
    • 当 Field 配置了 helpTextextraText 时,Field 组件会被自动添加 aria-describedby 属性,值为 helpText、extraText 所对应DOM元素的 id (格式:${props.field}-helpText${props.field}-extraText

文案规范

  • 表单标题
    • 表单标题需要跟随标题的书写规范
  • 表单标签
    • 标签是输入框的简短描述。标签不是注释信息(help text),因此不应该是输入框的填写说明
    • 标签必须要:
      • 放在输入框的上方或下方
      • 简短(1-3个词)
      • 使用语句的大小写规范(首字母大写,其他小写)
  • 帮助文本
    • 帮助文本使用语句书写规范,首字母大写
  • 表单按钮
✅ 推荐用法❌ 不推荐用法

设计变量

FAQ

  • 为什么我声明了表单,对值进行了修改,数据没有自动映射到 formState.values 中?
    请检查是否正确传入了 field,Field 上的field属性是必填项!!!
  • 为什么传入了 defaultValue、defaultChecked 不生效?
    请参考文档开头表单控件,Form.Field 组件对默认值做了统一处理,你应该使用initValue或者initValues来传入默认值
  • 为什么异步更新了 initValue、initValues 后,组件没有发生变化,值没有生效?
    initValueinitValues只在 Field、Form mounted 时进行消费,后续做的异步更新并不会起效。
    如果你的初始值需要从远程取,那么你可以在获取到值之后,使用formApi.setValue/setValues进行更新。
    或者直接给 Form、Field 传入一个新的key强制它重新挂载
  • 为什么调用了 formApi.setValues 更新 fields 的值,但是实际渲染并没有更新?
    setValues 默认情况下对尚未存在的 field 进行赋值不会生效。如果你的 fields 是动态加载的话,请检查在 setValues 时,该 field 是否已 mounted。
    如有需要,可以使用 override 模式 formApi.setValues(newValue, { isOverride: true })
  • 为什么 rules 中的 validator 校验失败,但是对应的错误信息没有被展示?
    async-validator 的自定义 validator 返回值必须是 boolean 类型,否则它不执行任何回调,semi 后续的钩子也不会被调用。建议通过加 !! 或者 Boolean() 强制转换返回类型
  • 为什么 getValues 拿不到某个 field?
    field 没有初始值的话,getValues 获取不到这一项。可以设置 initValues/initValue 或者给 form 设置 allowEmpty 属性。
  • 为什么在输入框(Input、TagInput……)上敲击 enter 回车键会触发了 Form 的 submit?
    这个是标准 HTML 行为,我们不计划进行干预,会与原生保持一致。如果表单内确实只有一个 Input 元素,又不想回车时触发 submit 回调,建议对 Input 的 keydown 事件的 enter 采取 preventDefault 阻止默认行为。
    点击 #767 查看相关背景和内容。
  • 表单会自动保存历史输入项,不想要这个功能怎么办?
    在 v2.3 之前,Form 并没有严格按照 A11y 无障碍标准为输入控件配置fornameid 等属性,因此在之前的版本并没有该功能。v2.3 后我们严格按照 W3C 标准进行了实现。如果你不希望浏览器自动保存历史输入项,也可以通过在 Form 级别或者 Field 级别设置 autoComplete=off 关掉