diff --git a/packages/vantui-doc/src/form/README.md b/packages/vantui-doc/src/form/README.md
index f7a40802f..79327d43d 100644
--- a/packages/vantui-doc/src/form/README.md
+++ b/packages/vantui-doc/src/form/README.md
@@ -156,6 +156,65 @@ function Demo() {
}
```
+### 支持多层级数据结构
+
+FormItem 的 name 属性支持数组的形式, 数组项为字符串的时候挂载到对象上,为数字的时候挂载到数组上
+第一层固定为对象
+
+```jsx
+function Demo() {
+ const formIt = react.useRef(null)
+
+ const multFormItems = function () {
+ let jsx = []
+ for (let i = 0; i < 2; i++) {
+ jsx.push(
+ <>
+ e.detail.value}
+ >
+
+
+ e.detail.value}
+ >
+
+
+ >,
+ )
+ }
+ return jsx
+ }
+
+ return (
+
+ )
+}
+```
+
### 异步处理和自定义校验
- Uploader 的 onAfterRead 事件只返回变更的文件,展示的是多个文件的话需要重新设置
diff --git a/packages/vantui/src/form-item/index.tsx b/packages/vantui/src/form-item/index.tsx
index 645f3999b..f5e88ac40 100644
--- a/packages/vantui/src/form-item/index.tsx
+++ b/packages/vantui/src/form-item/index.tsx
@@ -37,6 +37,7 @@ export function FormItem(props: FormItemProps) {
const formInstance = useContext(FormContext)
const { registerValidateFields, dispatch, unRegisterValidate } = formInstance
const [, forceUpdate_] = useState({})
+ const _name = Array.isArray(name) ? name.join('.') : name
const onStoreChange = useMemo(() => {
const onStoreChange = {
@@ -50,29 +51,29 @@ export function FormItem(props: FormItemProps) {
useEffect(() => {
/* 注册表单 */
- name &&
- registerValidateFields(name, onStoreChange, { rules, required, label })
+ _name &&
+ registerValidateFields(_name, onStoreChange, { rules, required, label })
return function () {
- name && unRegisterValidate(name)
+ _name && unRegisterValidate(_name)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [onStoreChange])
const getControlled = (child: any) => {
const props = { ...child.props }
- if (!name) return props
+ if (!_name) return props
const trigger_ = props[trigger]
const handleChange = async (e: any) => {
let value = null
if (valueFormat) {
- value = await valueFormat(e, name, formInstance)
+ value = await valueFormat(e, _name, formInstance)
} else {
value = e.detail
}
- dispatch({ type: 'setFieldsValue' }, name, value)
+ dispatch({ type: 'setFieldsValue' }, _name, value)
if (trigger_) trigger_(e)
}
props[trigger] = handleChange
@@ -82,10 +83,10 @@ export function FormItem(props: FormItemProps) {
await handleChange(e)
}
- dispatch({ type: 'validateFieldValue' }, name)
+ dispatch({ type: 'validateFieldValue' }, _name)
}
}
- props[valueKey] = dispatch({ type: 'getFieldValue' }, name)
+ props[valueKey] = dispatch({ type: 'getFieldValue' }, _name)
return props
}
@@ -112,7 +113,7 @@ export function FormItem(props: FormItemProps) {
diff --git a/packages/vantui/src/form/core/formstore.ts b/packages/vantui/src/form/core/formstore.ts
index 20cbdf17d..27ceb8530 100644
--- a/packages/vantui/src/form/core/formstore.ts
+++ b/packages/vantui/src/form/core/formstore.ts
@@ -3,6 +3,7 @@ import { unstable_batchedUpdates } from 'react-dom'
import { IFormInstanceAPI } from '../../../types/form'
type IAPI = keyof IFormInstanceAPI
+type Iname = string | Array
/* 对外接口 */
const formInstanceApi = [
@@ -82,10 +83,11 @@ class FormStore {
}
registerValidateFields(
- name: string,
+ name_: Iname,
control: Record,
model: Record,
): void {
+ const name = Array.isArray(name_) ? name_.join('.') : name_
if (this.defaultFormValue[name])
model['value'] = this.defaultFormValue[name]
const validate = FormStore.createValidate(model)
@@ -93,12 +95,14 @@ class FormStore {
this.control[name] = control
}
- unRegisterValidate(name: string) {
+ unRegisterValidate(name_: Iname) {
+ const name = Array.isArray(name_) ? name_.join('.') : name_
delete this.model[name]
delete this.control[name]
}
- notifyChange(name: string) {
+ notifyChange(name_: Iname) {
+ const name = Array.isArray(name_) ? name_.join('.') : name_
const controller = this.control[name]
if (controller) controller?.changeValue()
}
@@ -110,7 +114,8 @@ class FormStore {
})
}
- setFieldsValue(name: string, modelValue: any): any {
+ setFieldsValue(name_: Iname, modelValue: any): any {
+ const name = Array.isArray(name_) ? name_.join('.') : name_
const model = this.model[name]
if (!model) return false
if (toString.call(modelValue) === '[Object, object]' && modelValue.value) {
@@ -125,18 +130,62 @@ class FormStore {
}
}
- setValueClearStatus(model: Record, name: string, value: any) {
+ setValueClearStatus(model: Record, name_: Iname, value: any) {
+ const name = Array.isArray(name_) ? name_.join('.') : name_
+
model['value'] = value
model['status'] = 'pendding'
this.notifyChange(name)
}
+ static transformMultilevelData(data: Record) {
+ const keys = Object.keys(data)
+ const hasMultiLevel = keys.some((item) => item.includes('.'))
+ if (hasMultiLevel) {
+ const res: Record = {}
+ for (let i = 0; i < keys.length; i++) {
+ const key = keys[i]
+ if (key) {
+ if (!key?.includes('.')) {
+ res[key] = data[key]
+ } else {
+ const ks = key.split('.')
+ let p = res
+ for (let j = 0; j < ks.length; j++) {
+ const k = ks[j] as string | number
+ if (p[k] && j !== ks.length - 1) {
+ p = p[k]
+ } else if (!p[k] && j !== ks.length - 1) {
+ const nextK = ks[j + 1] as string | number
+ if (
+ !isNaN(Number(nextK)) &&
+ typeof Number(nextK) === 'number'
+ ) {
+ p[k] = []
+ } else if (typeof nextK === 'string') {
+ p[k] = {}
+ }
+ p = p[k]
+ } else {
+ p[k] = data[key]
+ }
+ }
+ }
+ }
+ }
+
+ return res
+ } else {
+ return data
+ }
+ }
+
getFieldsValue() {
const formData: any = {}
Object.keys(this.model).forEach((modelName) => {
formData[modelName] = this.model[modelName].value
})
- return formData
+ return FormStore.transformMultilevelData(formData)
}
resetFields() {
@@ -145,19 +194,25 @@ class FormStore {
})
}
- getFieldModel(name: string) {
+ getFieldModel(name_: Iname) {
+ const name = Array.isArray(name_) ? name_.join('.') : name_
+
const model = this.model[name]
return model ? model : {}
}
- getFieldValue(name: string) {
+ getFieldValue(name_: Iname) {
+ const name = Array.isArray(name_) ? name_.join('.') : name_
+
const model = this.model[name]
if (!model && this.defaultFormValue[name])
return this.defaultFormValue[name]
return model ? model.value : null
}
- validateFieldValue(name: string, forceUpdate = true) {
+ validateFieldValue(name_: Iname, forceUpdate = true) {
+ const name = Array.isArray(name_) ? name_.join('.') : name_
+
const model = this.model[name]
/* 记录上次状态 */
const lastStatus = model.status
diff --git a/packages/vantui/types/form.d.ts b/packages/vantui/types/form.d.ts
index c69264433..72f5cad94 100644
--- a/packages/vantui/types/form.d.ts
+++ b/packages/vantui/types/form.d.ts
@@ -38,7 +38,7 @@ export interface FormItemProps extends StandardProps {
/**
* @description 对应表单字段名
*/
- name: string
+ name: string | Array
/**
* @description 第一级操作表单组件
*/
@@ -107,7 +107,7 @@ export interface FormItemProps extends StandardProps {
*/
valueFormat?: (
value: any,
- name: string,
+ name: string | Array,
IFormInstance: IFormInstanceAPI,
) => any
/**
@@ -127,7 +127,7 @@ export type IFormInstanceAPI = {
* @description 注册校验规则
*/
registerValidateFields: (
- name: string,
+ name: string | Array,
control: Record,
model: Record,
) => void
@@ -138,7 +138,7 @@ export type IFormInstanceAPI = {
/**
* @description 注册校验规则
*/
- unRegisterValidate: (name: string) => void
+ unRegisterValidate: (name: string | Array) => void
/**
* @description 重置表单
*/
@@ -150,7 +150,10 @@ export type IFormInstanceAPI = {
/**
* @description 设置单个表单值
*/
- setFieldsValue: (name: string, modelValue: any) => any
+ setFieldsValue: (
+ name: string | Array,
+ modelValue: any,
+ ) => any
/**
* @description 获取所有表单值
*/
@@ -158,7 +161,7 @@ export type IFormInstanceAPI = {
/**
* @description 获取单个表单值
*/
- getFieldValue: (name: string) => any
+ getFieldValue: (name: string | Array) => any
/**
* @description 校验表单,并获取错误信息和所有表单值
*/
@@ -175,7 +178,11 @@ export type IFormInstanceAPI = {
) => void,
) => void
} & {
- dispatch: (params: { type: string }, name?: string, ...arg: any[]) => any
+ dispatch: (
+ params: { type: string },
+ name?: string | Array,
+ ...arg: any[]
+ ) => any
setCallback: Record<
string,
undefined | ((values?: Record) => void)