From 05fd3e03a5ac28f381915fcaca12479d39e0dd8a Mon Sep 17 00:00:00 2001 From: moecasts Date: Fri, 1 Nov 2024 21:03:36 +0800 Subject: [PATCH] feat(form): add getValidateMessage api re #2885 --- src/form/FormItem.tsx | 6 + src/form/_example/base.tsx | 27 ++++- src/form/form.md | 207 --------------------------------- src/form/hooks/useInstance.tsx | 26 +++++ src/form/type.ts | 4 + 5 files changed, 59 insertions(+), 211 deletions(-) diff --git a/src/form/FormItem.tsx b/src/form/FormItem.tsx index 9151499b53..72eb10bfb1 100644 --- a/src/form/FormItem.tsx +++ b/src/form/FormItem.tsx @@ -45,6 +45,7 @@ export interface FormItemInstance { validate?: Function; resetField?: Function; setValidateMessage?: Function; + getValidateMessage?: Function; resetValidate?: Function; validateOnly?: Function; isFormList?: boolean; @@ -382,6 +383,10 @@ const FormItem = forwardRef((originalProps, ref setVerifyStatus(status); } + function getValidateMessage() { + return errorList; + } + useEffect(() => { // 注册自定义更新回调 if (!shouldUpdate || !form) return; @@ -459,6 +464,7 @@ const FormItem = forwardRef((originalProps, ref validateOnly, resetField, setValidateMessage, + getValidateMessage, resetValidate: resetHandler, }; useImperativeHandle(ref, (): FormItemInstance => instance); diff --git a/src/form/_example/base.tsx b/src/form/_example/base.tsx index 2c6eacc313..df93313027 100644 --- a/src/form/_example/base.tsx +++ b/src/form/_example/base.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import { Form, Input, Radio, Checkbox, Button, Switch, MessagePlugin, DatePicker, Tooltip, Space } from 'tdesign-react'; import type { FormProps } from 'tdesign-react'; @@ -17,6 +17,7 @@ export default function BaseForm() { if (e.validateResult === true) { MessagePlugin.info('提交成功'); } + form.getValidateMessage?.(); }; const onReset: FormProps['onReset'] = (e) => { @@ -32,15 +33,33 @@ export default function BaseForm() { ]); }; + useEffect(() => { + form.getValidateMessage?.(); + }, [form]); + return (
- + + { + console.log('debug1 111', form.getValidateMessage?.(['name'])); + }} + > + log error 1 + + { + console.log('debug1 222', form.getValidateMessage?.()); + }} + > + log error 2 + - + - + 男性 女性 diff --git a/src/form/form.md b/src/form/form.md index 5f5be5414a..0e17a35ba5 100644 --- a/src/form/form.md +++ b/src/form/form.md @@ -1,209 +1,2 @@ :: BASE_DOC :: -### 复杂嵌套数据结构表单 - -可给 `name` 传入数组整理成对象嵌套数据结构。 - -{{ nested-data }} - -### 动态增减嵌套表单 - -可使用 `Form.FormList` 组件创建动态表单。 - -{{ form-list }} - -### 字段联动的表单 - -在某些特定场景,例如修改某个字段值后出现新的字段选项、或者纯粹希望表单任意变化都对某一个区域进行渲染。你可以通过 `shouldUpdate` 修改 `FormItem` 的更新逻辑。 - -{{ form-field-linkage }} - -### 自定义表单控件 - -可以使用 `Form.FormItem` 包裹自定义组件并在组件中接受 `value` 和 `onChange` 的入参,实现自定义表单控件。 - -{{ customized-form-controls }} - -## Hooks - -### Form.useForm - -创建 Form 实例,用于管理所有数据状态。 - - -### Form.useWatch - -用于直接获取 form 中字段对应的值。 - -```js -const Demo = () => { - const [form] = Form.useForm(); - const userName = Form.useWatch('username', form); - - return ( - - - - - - ); -}; -``` - -## FAQ - -### 为什么被 FormItem 包裹的组件 value、defaultValue 没有效果? - -Form 组件设计的初衷是为了解放开发者配置大量的 `value`、`onChange` 受控属性,所以 Form.FormItem 被设计成需要拦截嵌套组件的受控属性,如需定义初始值请使用 `initialData` 属性。 - -由于 Form.FormItem 只会拦截第一层子节点的受控属性,所以如不希望 Form.FormItem 拦截受控属性希望自行管理 state 的话,可以在 Form.FormItem 下包裹一层 `div` 节点脱离 Form.FormItem 的代理,但同时也会失去 Form 组件的校验能力。 - -### 我只想要 Form 组件的布局效果,校验能力我自己业务来实现可以吗? - -可以的,Form 的校验能力只跟 `name` 属性关联,不指定 Form.FormItem 的 `name` 属性是可以当成布局组件来使用的,甚至可以实现各种嵌套自定义内容的布局效果。 - -```js -// 可以单独使用 FormItem 组件 - -
可以任意定制内容
- -
可以任意定制内容
-
-``` - -### getFieldsValue 返回的数据如何支持嵌套数据结构? - -将 `name` 设置成数组形式可以支持嵌套数据结构。 - -```js -// ['user', 'name'] => { user: { name: '' } } - - - -``` - -## API - -### Form Props - -名称 | 类型 | 默认值 | 描述 | 必传 --- | -- | -- | -- | -- -className | String | - | 类名 | N -style | Object | - | 样式,TS 类型:`React.CSSProperties` | N -colon | Boolean | false | 是否在表单标签字段右侧显示冒号 | N -disabled | Boolean | undefined | 是否禁用整个表单 | N -errorMessage | Object | - | 表单错误信息配置,示例:`{ idcard: '请输入正确的身份证号码', max: '字符长度不能超过 ${max}' }`。TS 类型:`FormErrorMessage` | N -form | Object | - | 经 `Form.useForm()` 创建的 form 控制实例。TS 类型:`FormInstanceFunctions` | N -formControlledComponents | Array | - | 允许表单统一控制禁用状态的自定义组件名称列表。默认会有组件库的全部输入类组件:TInput、TInputNumber、TCascader、TSelect、TOption、TSwitch、TCheckbox、TCheckboxGroup、TRadio、TRadioGroup、TTreeSelect、TDatePicker、TTimePicker、TUpload、TTransfer、TSlider。对于自定义组件,组件内部需要包含可以控制表单禁用状态的变量 `formDisabled`。示例:`['CustomUpload', 'CustomInput']`。TS 类型:`Array` | N -id | String | undefined | 表单原生的id属性,支持用于配合非表单内的按钮通过form属性来触发表单事件 | N -initialData | Object | - | 表单初始数据,重置时所需初始数据,优先级小于 FormItem 设置的 initialData | N -labelAlign | String | right | 表单字段标签对齐方式:左对齐、右对齐、顶部对齐。可选项:left/right/top | N -labelWidth | String / Number | '100px' | 可以整体设置label标签宽度,默认为100px | N -layout | String | vertical | 表单布局,有两种方式:纵向布局 和 行内布局。可选项:vertical/inline | N -preventSubmitDefault | Boolean | true | 是否阻止表单提交默认事件(表单提交默认事件会刷新页面),设置为 `true` 可以避免刷新 | N -requiredMark | Boolean | true | 是否显示必填符号(*),默认显示 | N -resetType | String | empty | 重置表单的方式,值为 empty 表示重置表单为空,值为 initial 表示重置表单数据为初始值。可选项:empty/initial | N -rules | Object | - | 表单字段校验规则。TS 类型:`FormRules` `type FormRules = { [field in keyof T]?: Array }`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/form/type.ts) | N -scrollToFirstError | String | - | 表单校验不通过时,是否自动滚动到第一个校验不通过的字段,平滑滚动或是瞬间直达。值为空则表示不滚动。可选项:''/smooth/auto | N -showErrorMessage | Boolean | true | 校验不通过时,是否显示错误提示信息,统一控制全部表单项。如果希望控制单个表单项,请给 FormItem 设置该属性 | N -statusIcon | TNode | undefined | 校验状态图标,值为 `true` 显示默认图标,默认图标有 成功、失败、警告 等,不同的状态图标不同。`statusIcon` 值为 `false`,不显示图标。`statusIcon` 值类型为渲染函数,则可以自定义右侧状态图标。TS 类型:`boolean \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N -submitWithWarningMessage | Boolean | false | 【讨论中】当校验结果只有告警信息时,是否触发 `submit` 提交事件 | N -onReset | Function | | TS 类型:`(context: { e?: FormResetEvent }) => void`
表单重置时触发 | N -onSubmit | Function | | TS 类型:`(context: SubmitContext) => void`
表单提交时触发。其中 `context.validateResult` 表示校验结果,`context.firstError` 表示校验不通过的第一个规则提醒。`context.validateResult` 值为 `true` 表示校验通过;如果校验不通过,`context.validateResult` 值为校验结果列表。
【注意】⚠️ 默认情况,输入框按下 Enter 键会自动触发提交事件,如果希望禁用这个默认行为,可以给输入框添加 enter 事件,并在事件中设置 `e.preventDefault()`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/form/type.ts)。
`interface SubmitContext { e?: FormSubmitEvent; validateResult: FormValidateResult; firstError?: string; fields?: any }`

`type FormValidateResult = boolean \| ValidateResultObj`

`type ValidateResultObj = { [key in keyof T]: boolean \| ValidateResultList }`

`type ValidateResultList = Array`

`type AllValidateResult = CustomValidateObj \| ValidateResultType`

`interface ValidateResultType extends FormRule { result: boolean }`

`type ValidateResult = { [key in keyof T]: boolean \| ErrorList }`

`type ErrorList = Array`
| N -onValuesChange | Function | | TS 类型:`(changedValues: Record, allValues: Record) => void`
字段值更新时触发的回调事件 | N - -### FormInstanceFunctions 组件实例方法 - -名称 | 参数 | 返回值 | 描述 --- | -- | -- | -- -className | String | - | 类名 | N -style | Object | - | 样式,TS 类型:`React.CSSProperties` | N -clearValidate | `(fields?: Array)` | \- | 必需。清空校验结果。可使用 fields 指定清除部分字段的校验结果,fields 值为空则表示清除所有字段校验结果。清除邮箱校验结果示例:`clearValidate(['email'])` -currentElement | \- | `HTMLFormElement` | 必需。获取 form dom 元素 -getFieldValue | `(field: NamePath) ` | `unknown` | 必需。获取单个字段值 -getFieldsValue | \- | `getFieldsValue` | 必需。获取一组字段名对应的值,当调用 getFieldsValue(true) 时返回所有表单数据。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/form/type.ts)。
`interface getFieldsValue{ (nameList: true): T; (nameList: any[]): Record;}`
-reset | `(params?: FormResetParams)` | \- | 必需。重置表单,表单里面没有重置按钮`