JGuang

表单

Form · Arco Design

交互预览
npm install @arco-design/web-react@2.66.18

表单 Form

具有数据收集、校验和提交功能的表单,包含复选框、单选框、输入框、下拉选择框等元素。

安装

npm install @arco-design/web-react@2.66.18

在入口引入 @arco-design/web-react/dist/css/arco.css,用 ConfigProvider 设置语言。React 19 项目还需在入口最先引入 @arco-design/web-react/es/_util/react-19-adapter,否则 Message、Modal 等命令式 API 无法渲染。

示例

  • 基础用法:非受控模式的用法。
  • 表单布局:Form 支持三种排列方式: horizontal 水平排列 (默认)、 vertical 垂直排列、 inline 行内排列
  • 受控表单:可以在Form.Item传入field属性,即可使控件变为受控组件,表单项的值都将会被 Form 收集。 <ol> <li> 受控模式下Form.Item会接管控件,自动给表单控件添加相应的 value(或 triggerPropName 指定的其他属性)和onChange(或 trigger 指定的其他属性),所有的数据收集都由 Form 内部完成。 </li> <li> 受控下不要为表单控件添加 defaultValue。默认值可以通过 Form 的 initialValues 或 Form.Item 的 initialValue 来设置。 </li> </ol>
  • 表单方法调用:在函数式组件里可以使用Form.useForm获取表单实例。通过该实例调用表单方法,例如设置表单字段值,重置表单等。 在类组件里可以使用ref 获取表单实例。
  • 控制表单项错误状态:通过 setFields 方法的 error 参数,可以在外部控制表单项的错误状态。
  • 复杂类型的数据:通过设置 field 为 a.b.c 格式,可以得到 {a:{b:{c: xx}}}。
  • 表单控件嵌套:Form.Item 可以互相嵌套。
  • 表单控件联动:可以通过shouldUpdate 实现控件间的联动。
  • 动态增减表单项:通过Form.List管理数组类型的表单结构。设置校验规则时 Form.List 会渲染出额外的 DOM 节点用来展示校验信息,如果不需要可以传入 noStyle=false,并通过 Form.useFormState 自定义校验信息的展示。
  • 动态增减嵌套类型的表单项:通过Form.List管理数组类型的表单结构。可以通过对 field 进行一些处理,实现动态增减复杂类型的表单项
  • 自定义表单控件:Form.Item 会给自己的直接子节点(必须是唯一子节点)传递 onChange 和 value 属性,自定义控件只有在调用这个onChange 之后,自己的值才能被 Form.Item 收集到 。
  • 处理表单项的值:首先,在使用受控表单时,所有表单项的值在改变时,都会被 Form 收集到。如果需要对表单项的值进行处理后再存储在 Form 中,可以使用 normalize 属性。与之相对,在进行表单项的渲染时,都会从 Form 中取值,并作为 value 属性传递给对应的表单项,如果需要对从 Form 中取出的值进行转换再传递给表单项,可以使用 formatter 属性。注意:form.setFieldValue不会触发normalize。
  • 注册表单:填写必须的信息以注册新用户
  • 全局禁用:给 Form 组件设置 disabled 可以全局禁用所有表单控件。
  • 不同尺寸:通过 size 属性可以设置不同尺寸的表单
  • 自定义表单校验状态:Form.Item 支持通过 hasFeedbackvalidateStatus 和 help 属性自定义表单校验状态及校验文案。
  • 表单校验:可以通过 form.validate 方法进行表单字段的校验。可以通过参数指定校验特定字段。
  • 表单异步校验:在 rules 中自定义 validator 方法,并返回一个 Promise 即可实现表单的异步校验。 p.s: 如果用 lodash.debounce 不生效,建议使用 debounce.promise ,它返回的是一个 promise。
  • 表单校验信息模板:可以通过 validateMessages 属性设置校验信息提示模板(2.32.0支持)。示例 也可以在 ConfigProvider 组件的 componentConfig 参数,为全局的 Form 组件设置 validateMessages 。
  • 滚动到指定表单字段
  • 表单校验失败不阻塞提交:可以通过 validateLevel 设置表单校验失败是显示为 warning 状态,不阻塞表单提交。
  • 多表单联动:可以通过 Form.Provider 组件管理多个表单的数据。2.30.0 支持。需要想要获得对应的表单实例,需要为 Form 组件设置 id 属性。
  • useWatch:可以通过 Form.useWatch 监听表单内部字段值的变动。(2.33.0 支持)
  • 获取表单上下文:在函数式组件里可以使用 Form.useFormContext 获取 Form 组件上下文,便于表单控件的封装。(version 2.33.0, isSubmitting in 2.44.0). isSubmitting 仅在通过 type=submit 的 button 触发表单 Form 的 onSubmit 属性进行提交时有效。如果 onSubmit 内部包含异步逻辑,请返回一个 Promise.
  • useFormState:可以通过 Form.useFormState 监听表单内部状态的变动。(2.44.0 支持)

示例来自 Arco Design 官方仓库(MIT),固定在 npm 2.66.18 对应的提交;部分示例使用在线图片或上传地址,预览中网络请求被禁用。

API

Form

参数名描述类型默认值版本
disabled统一配置表单控件是否可用boolean--
id设置后,会作为表单控件 id的前缀。string--
labelAlign标签的文本对齐方式'left' | 'right'right-
layout表单的布局,有三种布局,水平、垂直、多列。'horizontal' | 'vertical' | 'inline'horizontal-
requiredSymbol是否在 required 的时候显示加重的红色星号,设置 position 可选择将星号置于 label 前/后boolean | { position: 'start' | 'end' }trueposition in 2.24.0
size不同尺寸。'mini' | 'small' | 'default' | 'large'--
colon是否显示标签后的一个冒号,优先级小于 Form.Item 中 colon 的优先级。(ReactNode in v2.41.0)boolean | ReactNode--
className节点类名string | string[]--
formformFormInstance<FormData, FieldValue, FieldKey>--
initialValues设置表单初始值Partial<FormData>--
labelCol<label>标签布局,同<Grid.Col>组件接收的参数相同,可以配置span和offset值,会覆盖全局的labelCol设置ColProps{ span: 5, offset: 0 }-
onChange表单项值改变时候触发。和 onValuesChange 不同的是只会在用户操作表单项时触发(value: Partial<FormData>, values: Partial<FormData>) => void--
onValuesChange任意表单项值改变时候触发。第一个参数是被改变表单项的值,第二个参数是所有的表单项值(value: Partial<FormData>, values: Partial<FormData>) => void--
scrollToFirstError验证失败后滚动到第一个错误字段。(ScrollIntoViewOptions 类型在 2.19.0 开始支持)boolean | ScrollIntoViewOptions--
style节点样式CSSProperties--
validateMessages校验提示信息模板 demoPartial<{[key in keyof ValidateMessagesTemplateType]: ValidateMessagesTemplateType[key] extends string? ValidateMessagesTemplateType[key] | ((data, { label }) => any): Partial<Record<keyof ValidateMessagesTemplateType[key], string | ((data, { label }) => any)>>;}>-2.32.0
validateTrigger触发验证的时机。string | string[]onChange2.28.0
wrapper配置最外层标签,可以是 html 标签或是组件ComponentTypeform-
wrapperCol控件布局,同labelCol的设置方法一致,会覆盖全局的wrapperCol设置,ColPropsColProps{ span: 19, offset: 0 }-
wrapperProps配置 wrapper 之后,可以传一些参数到 wrapper 上。IndexedObject--
onSubmit数据验证成功后回调事件(values: FormData) => void--
onSubmitFailed数据验证失败后回调事件(errors: { [key: string]: FieldError }) => void-2.21.0

Form.Item

参数名描述类型默认值版本
disabled是否禁用,优先级高于 Form 的 disabled 属性boolean--
hasFeedback是否显示校验图标,配置 validateStatus 使用。boolean--
hidden隐藏表单项. 表单字段值仍然会被获取boolean-2.29.0
required是否必选,会在 label 标签前显示加重红色符号,如果这里不设置,会从 rules 中寻找是否是 requiredboolean--
trigger接管子节点,搜集子节点值的时机。stringonChange-
triggerPropName子节点被接管的值的属性名,默认是 value,比如 <Checkbox> 为 checked。stringvalue-
labelAlign标签的文本对齐方式,优先级高于 Form'left' | 'right'right-
layout布局'horizontal' | 'vertical' | 'inline'--
requiredSymbol是否在 required 的时候显示加重的红色星号,设置 position 可选择将星号置于 label 前/后boolean | { position: 'start' | 'end' }trueposition in 2.24.0
validateStatus校验状态'success' | 'warning' | 'error' | 'validating'--
colon是否显示标签后的一个冒号,优先级小于 Form.Item 中 colon 的优先级。(ReactNode in v2.41.0)boolean | ReactNode--
extra额外的提示内容。ReactNode--
help自定义校验文案ReactNode--
label标签的文本ReactNode--
childrenReactNode 类型与函数类型的 childrenReact.ReactNode | FormItemChildrenFn<FormData, FieldValue, FieldKey>--
className节点类名string | string[]--
dependencies设置依赖字段。当依赖的字段值改变时,触发自身的校验。如果是想动态渲染某个表单控件/表单区域,使用 shouldUpdatestring[]-2.40.0
field受控组件的唯一标示FieldKey--
initialValue设置控件初始值.(初始值,请不要使用受控组件的defaultValue了)FieldValue--
labelCol<label>标签布局,同<Grid.Col>组件接收的参数相同,可以配置span和offset值,会覆盖全局的labelCol设置ColProps--
normalize将控件的 value 进行一定的转换再保存到form中。(value: FieldValue | undefined,prevValue: FieldValue | undefined,allValues: Partial<FormData>) => any--
noStyle不渲染任何外部标签/样式,只进行字段绑定。注意: 设置该属性为true时,该字段若未通过校验,错误信息将不会显示出来。可以传入对象,并设置 showErrorTip( 2.5.0 开始支持) 为true,错误信息将会展示在上层 formItem 节点下。boolean | { showErrorTip: boolean }--
rules受控模式下的验证规则,RulesPropsRulesProps<FieldValue>[]--
shouldUpdate是否在其他控件值改变时候重新渲染当前区域。设置为true时候,表单的任意改变都会重新渲染该区域。| boolean| ((prevValues: Partial<FormData>,currentValues: Partial<FormData>,info: {isFormList?: boolean;field?: FieldKey | FieldKey[];isInner?: boolean;}) => boolean)--
style节点样式CSSProperties--
tooltip提示文本ReactNode | (TooltipProps & { icon?: ReactElement })-2.43.0
validateTrigger触发验证的时机。取值和跟包裹的控件有关系,控件支持的触发事件,都可以作为值。例如Input支持的 onFocus、 onBlur、 onChange 都可以作为 validateTrigger 的值。传递为 [] 时,仅会在调用表单 validate 方法时执行校验规则。string | string[]onChange-
wrapperCol控件布局,同labelCol的设置方法一致,会覆盖全局的wrapperCol设置,ColPropsColProps--
formatter将Form内保存的当前控件对应的值进行一定的转换,再传递给控件。(value: FieldValue | undefined) => any-2.23.0
getValueFromEvent指定在子节点触发onChange事件时如何处理值。(如果自定义了trigger属性,那么这里的参数就是对应的事件回调函数的参数类型)(...args) => FieldValue-2.23.0

Form.List

参数名描述类型默认值版本
noStyleFormItemProps['noStyle'].rules 存在时默认为 false(需要渲染校验信息),否则默认为 trueFormItemProps['noStyle']-2.46.0
field字段名FieldKey (必填)--
initialValue初始值SubFieldValue[]-2.22.0
rules受控模式下的验证规则,RulesPropsRulesProps<SubFieldValue[]>[]-2.46.0
children函数类型的 children(fields: { key: number; field: SubFieldKey }[],operation: {add: (defaultValue?: SubFieldValue, index?: number) => void;remove: (index: number) => void;move: (fromIndex: number, toIndex: number) => void;}) => React.ReactNode--

Form.Provider(2.30.0)

参数名描述类型默认值
onFormSubmit包裹的任意 Form 组件触发提交时,该方法会被调用(id: string | undefined,values,{forms,}: {forms: {[key: string]: FormInstance;};}) => void-
onFormValuesChange包裹的任意 Form 组件的值改变时,该方法会被调用(id: string | undefined,changedValues,{forms,}: {forms: {[key: string]: FormInstance;};}) => void-

FormInstance

export type FormInstance<
  FormData = any,
  FieldValue = FormData[keyof FormData],
  FieldKey extends KeyType = keyof FormData
> = Pick<
  Store<FormData, FieldValue, FieldKey>,
  | "getFieldsValue"
  | "getFieldValue"
  | "getFieldError"
  | "getFieldsError"
  | "getTouchedFields"
  | "getFields"
  | "setFieldValue"
  | "setFieldsValue"
  | "setFields"
  | "resetFields"
  | "clearFields"
  | "submit"
  | "validate"
  | "getFieldsState"
> & {
  scrollToField: (field: FieldKey, options?: ScrollIntoViewOptions) => void;
  // arco 内部使用,业务万不可调用
  getInnerMethods: (
    inner?: boolean
  ) => InnerMethodsReturnType<FormData, FieldValue, FieldKey>;
};

InnerMethodsReturnType

export type InnerMethodsReturnType<
  FormData = any,
  FieldValue = FormData[keyof FormData],
  FieldKey extends KeyType = keyof FormData
> = Pick<
  Store<FormData, FieldValue, FieldKey>,
  | "registerField"
  | "registerStateWatcher"
  | "registerFormWatcher"
  | "registerWatcher"
  | "innerSetInitialValues"
  | "innerSetInitialValue"
  | "innerSetCallbacks"
  | "innerSetFieldValue"
  | "innerGetStore"
  | "innerGetStoreStatus"
  | "innerCollectFormState"
  | "innerGetFieldValue"
>;

ComponentType

export type ComponentType =
  | keyof JSX.IntrinsicElements
  | React.ComponentType<any>;

IndexedObject

export type IndexedObject = {
  [key: string]: any;
};

FieldError

export type FieldError<FieldValue = any> = {
  value?: FieldValue;
  message?: ReactNode;
  type?: string;
  requiredError?: boolean;
};

FormItemChildrenFn

export type FormItemChildrenFn<
  FormData = any,
  FieldValue = FormData[keyof FormData],
  FieldKey extends KeyType = keyof FormData
> = (
  formData: any,
  form: FormInstance<FormData, FieldValue, FieldKey>
) => React.ReactNode;

Rules

底层使用 b-validate。

export interface RulesProps {
  // 触发校验的时机
  validateTrigger?: string | string[];
  // 校验失败时候以 `error` 或 `warning` 形式展示错误信息。当设置为 `warning` 时不会阻塞表单提交
  validateLevel?: 'error' | 'warning';
  required?: boolean;
  type?: string;
  length?: number;
  // Array
  maxLength?: number;
  minLength?: number;
  includes?: boolean;
  deepEqual?: any;
  empty?: boolean;
  // Number
  min?: number;
  max?: number;
  equal?: number;
  positive?: boolean;
  negative?: boolean;
  // Object
  hasKeys?: string[];
  // String
  match?: RegExp;
  uppercase?: boolean;
  lowercase?: boolean;
  // Boolean
  true?: boolean;
  false?: boolean;
  // custom
  validator?: (value, callback: (error?: ReactNode) => void) => void;
  message?: string;
}

this.form

通过ref可以拿到this.form,this.form包含了表单的验证、设值等常用操作。

<Form ref={(ref) => (this.form = ref)}>
  <FormItem>...</FormItem>
</Form>
方法描述类型版本
validate校验并获取表单输入域的值与 Errors,如果不设置 fields 的话,会验证所有的 fields。支持 callback 和 promise 两种使用方法。Function(fields?: string[], callback(errors, values) => void)
submit提交表单Function
setFieldValue设置一个表单控件的值Function(field: string, value)
setFields设置一组表单控件的值和报错。Function({ [field]: string: { value: any, error: FieldError } })
setFieldsValue设置多个表单控件的值Function({[field]: string, value})
getFieldValue获取一个表单控件的值。请不要把返回值直接作为 useEffect 的依赖,其返回值会被深克隆,引用地址会发生改变Function(field: string)
getFields获取全部表单项的值,包括被创建后销毁的表单项。请不要把返回值直接作为 useEffect 的依赖,其返回值会被深克隆,引用地址会发生改变Function
getFieldsValue获取一组表单控件的值,如果不设置 fields 的话,会获取所有的 fields。请不要把返回值直接作为 useEffect 的依赖,其返回值会被深克隆,引用地址会发生改变Function(fields: string[])
getFieldError获取一个表单控件的错误状态Function(field: string)
getFieldsError获取一组表单控件的错误状态,如果不设置 fields 的话,会获取所有的控件的错误状态。Function(fields?: string[])
scrollToField滚动到指定表单字段位置。ScrollIntoViewOptionsFunction(field: string, options?: ScrollIntoViewOptions)
getTouchedFields获取被操作过的字段() => string[]
resetFields重置表单控件的值变为初始值Function(field?: string[])
clearFields清除表单控件的值以及校验状态。等同于 form.setFields({ [field]: { value: undefined; error: null, warning: null } })Function(field?: string[])2.29.0

validate 用法

this.form.validate((errors, values) => {
  console.log(errors, values);
});
// 或者
this.form.validate().then((values) => {
  console.log(values);
}).catch((error) => {
  console.log(error.name);
  console.log(error.message);
  console.log(error.errors);
});
// 或者 (注意要在 async 方法中使用)
try {
  const values = await this.form.validate();
} catch (error) {
  console.log(error.name);
  console.log(error.message);
  console.log(error.errors);
}

setFields 用法

this.form.setFields({
  name: {
    value: 'pjy',
    error: {
      message: 'Yes, I know!'
    },
    warning: 'warning...'
  }
});

常见问题

为什么无法调用 Modal 里嵌套的 Form 的方法?

例如以下使用方式:

// ...
const [form] = Form.useForm();
useEffect(() => {
  form.setFieldsValue({})
}, [])
return <div>
  <Modal visible={visible}>
    <Form form={form}>
      {/** ... */}
    </Form>
  </Modal>
</div>

这是因为在调用 form 的方法时,Modal 还未挂载,Form 还未创建。 可以设置 Modal 的 mountOnEnter=false 。

Form.Control

非常非常极其不建议直接使用Form.Control. 在1.15.0及以上版本,组件库对 Form.Item 进行了较多功能扩展,简化了受控表单的写法,不再推荐直接使用Form.Control 组件(当然1.x兼容了此写法)。但升级到2.0后,Form.Control作为Form的一个内部组件,为了功能升级或bugfix,可能会进行一些改动,较少考虑到外部直接使用的场景,所以非常建议使用Form.Item代替Form.Control。

如何设置表单控件的默认值?(为什么给控件例如 Input ,直接设置 defaultValue 不生效)

在被 FormItem包裹,并且 Form.Item 设置了 field 属性的控件上,不要再设置 defaultValue和 value 属性。 可以在 Form.Item 上通过 initialValue 来设置默认值。

Modal 默认在打开时挂载,所以页面加载完成时 Modal 还未挂载,Form 还未创建。 可以设置 Modal 的 mountOnEnter=false 。

传了 initialValue 但不生效。

initialValue 解释为初始值,只会在表单挂载时生效,如果表单数据是异步加载的请用 setFieldValue / setFieldsValue / setFields 更新表单值。

Form.Item 未收集到所包裹表单控件的值 / 未触发校验?

  • Form.Item 设置了 field 属性
  • Form.Item 直接包裹在表单控件外,并且表单控件是 FormItem 的唯一子节点
  • Form.Item 的默认 triggerPropName 是 value,表示会给子控件注入 value 属性。如果表单控件的受控属性是 checked(如 switch, checkbox, radio), fileList (如 Upload)或者其他,那么需要根据实际情况设置下 Form.Item 的 triggerPropName={表单控件的受控属性}
  • 类似 triggerPropName,默认 FormItem 监听子组件的 onChange 回调来收集控件值以及触发校验逻辑。如果子组件的回调不是 onChange ,记得设置下 FormItem 的 trigger={表单控件的事件回调}
  • Form.Item 所包裹的控件是挂载状态(即未被销毁)

某个表单元素填了值但已经被销毁,我如何获取这个值?

**getFields**方法会获取所有在 Form 中注册过的字段的值,包括被创建后销毁的表单项。

校验节流 或 异步校验?

在 rules 中自定义 validator 方法,并返回一个 Promise 即可实现表单的异步校验。 节流如果用 lodash.debounce 不生效,建议使用 debounce.promise ,它返回的是一个 promise。 官网示例

Form 中对 Checkbox/Switch/Upload 设置值不生效

在 Checkbox/Switch 对应的 Form.Item 上设置 triggerPropName=checked 在 Upload 对应的 Form.Item 上设置 triggerPropName=fileList 其他组件类似

Form 内 Input 出现浅蓝色背景色(Chrome 浏览器)?

蓝色背景色是 Chrome 浏览器的自动填充样式,关闭 form 的自动填充即可。

如何关闭自动填充?

Form 组件的原生属性,设置 autoComplete=off 即可。

点击 label 会触发对应表单控件的行为改变?如:switch 切换,checkbox 选中, input 聚焦

https://www.runoob.com/tags/tag-label.html 标签定义及使用说明 label 标签为 input 元素定义标注(标记)。 label 元素不会向用户呈现任何特殊效果。不过,它为鼠标用户改进了可用性。如果您在 label 元素内点击文本,就会触发此控件。就是说,当用户选择该标签时,浏览器就会自动将焦点转到和标签相关的表单控件上。 label 标签的 for 属性应当与相关元素的 id 属性相同。 如果实在不想要这个效果,给表单控件随便设置个 id 属性,不要和 label 的 for 属性一致即可。如 <Switch id="aaaaa" />

对错误信息的展示进行高级定制

https://codepen.io/yinkaihui/pen/GRwRQao?editors=1011

DatePicker.WeekPicker 传值解析不了

DatePicker.QuarterPicker 同理 给 Form.Item 加上 getValueFromEvent={(v, dv) => dv}。