Skip to content

Commit a065de4

Browse files
authored
feat: Form 自定义组件渲染 新增 opts: {disabled} 用于自定义渲染判断 示例: /comp/form/customerForm页面 (#2944)
* feat: Form 自定义组件渲染 示例: /comp/form/customerForm页面 1. 针对自定义渲染功能 FormSchema 中 render, renderColContent, renderComponentContent 新增 opts:{disabled} 扩展 帮助自定义渲染时做 条件判断、展示同步 渲染: ((renderCallbackParams) => any) ===> ((renderCallbackParams, opts) => any) 2. slot, colSlot 分别是 render, renderColContent 插槽,为方便插槽使用 slotFn 进行解构 #test={scope} scope==={...data, ...opts} * feat: Form 自定义组件渲染 示例: /comp/form/customerForm页面 1. 针对自定义渲染功能 FormSchema 新增 [fields] 和 [defaultValueObj] 帮助 render, renderColContent 自定义渲染时 存在多个 表单字段操作(复合field 场景)
1 parent fa5ecb0 commit a065de4

File tree

6 files changed

+226
-29
lines changed

6 files changed

+226
-29
lines changed

src/components/Form/src/components/FormItem.vue

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@
299299
return <Comp {...compAttr} />;
300300
}
301301
const compSlot = isFunction(renderComponentContent)
302-
? { ...renderComponentContent(unref(getValues)) }
302+
? { ...renderComponentContent(unref(getValues), { disabled: unref(getDisable) }) }
303303
: {
304304
default: () => renderComponentContent,
305305
};
@@ -333,7 +333,7 @@
333333
const { itemProps, slot, render, field, suffix, component } = props.schema;
334334
const { labelCol, wrapperCol } = unref(itemLabelWidthProp);
335335
const { colon } = props.formProps;
336-
336+
const opts = { disabled: unref(getDisable) };
337337
if (component === 'Divider') {
338338
return (
339339
<Col span={24}>
@@ -343,9 +343,9 @@
343343
} else {
344344
const getContent = () => {
345345
return slot
346-
? getSlot(slots, slot, unref(getValues))
346+
? getSlot(slots, slot, unref(getValues), opts)
347347
: render
348-
? render(unref(getValues))
348+
? render(unref(getValues), opts)
349349
: renderComponent();
350350
};
351351
@@ -391,12 +391,13 @@
391391
const realColProps = { ...baseColProps, ...colProps };
392392
const { isIfShow, isShow } = getShow();
393393
const values = unref(getValues);
394+
const opts = { disabled: unref(getDisable) };
394395
395396
const getContent = () => {
396397
return colSlot
397-
? getSlot(slots, colSlot, values)
398+
? getSlot(slots, colSlot, values, opts)
398399
: renderColContent
399-
? renderColContent(values)
400+
? renderColContent(values, opts)
400401
: renderItem();
401402
};
402403

src/components/Form/src/hooks/useFormEvents.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,13 @@ export function useFormEvents({
8787

8888
Object.keys(formModel).forEach((key) => {
8989
const schema = unref(getSchema).find((item) => item.field === key);
90+
const defaultValueObj = schema?.defaultValueObj;
91+
const fieldKeys = Object.keys(defaultValueObj || {});
92+
if (fieldKeys.length) {
93+
fieldKeys.map((field) => {
94+
formModel[field] = defaultValueObj![field];
95+
});
96+
}
9097
const isInput = schema?.component && defaultValueComponents.includes(schema.component);
9198
const defaultValue = cloneDeep(defaultValueRef.value[key]);
9299
formModel[key] = isInput ? defaultValue || '' : defaultValue;
@@ -96,14 +103,17 @@ export function useFormEvents({
96103
emit('reset', toRaw(formModel));
97104
submitOnReset && handleSubmit();
98105
}
99-
106+
// 获取表单fields
107+
const getAllFields = () =>
108+
unref(getSchema)
109+
.map((item) => [...(item.fields || []), item.field])
110+
.flat(1)
111+
.filter(Boolean);
100112
/**
101113
* @description: Set form value
102114
*/
103115
async function setFieldsValue(values: Recordable): Promise<void> {
104-
const fields = unref(getSchema)
105-
.map((item) => item.field)
106-
.filter(Boolean);
116+
const fields = getAllFields();
107117

108118
// key 支持 a.b.c 的嵌套写法
109119
const delimiter = '.';
@@ -340,8 +350,14 @@ export function useFormEvents({
340350
return unref(formElRef)?.validateFields(nameList);
341351
}
342352

343-
async function validate(nameList?: NamePath[] | undefined) {
344-
return await unref(formElRef)?.validate(nameList);
353+
async function validate(nameList?: NamePath[] | false | undefined) {
354+
let _nameList: any;
355+
if (nameList === undefined) {
356+
_nameList = getAllFields();
357+
} else {
358+
_nameList = nameList === Array.isArray(nameList) ? nameList : undefined;
359+
}
360+
return await unref(formElRef)?.validate(_nameList);
345361
}
346362

347363
async function clearValidate(name?: string | string[]) {

src/components/Form/src/hooks/useFormValues.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,16 @@ export function useFormValues({
127127
const schemas = unref(getSchema);
128128
const obj: Recordable = {};
129129
schemas.forEach((item) => {
130-
const { defaultValue } = item;
130+
const { defaultValue, defaultValueObj } = item;
131+
const fieldKeys = Object.keys(defaultValueObj || {});
132+
if (fieldKeys.length) {
133+
fieldKeys.map((field) => {
134+
obj[field] = defaultValueObj![field];
135+
if (formModel[field] === undefined) {
136+
formModel[field] = defaultValueObj![field];
137+
}
138+
});
139+
}
131140
if (!isNullOrUnDef(defaultValue)) {
132141
obj[item.field] = defaultValue;
133142

src/components/Form/src/types/form.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export interface FormActionType {
3939
first?: boolean | undefined,
4040
) => Promise<void>;
4141
validateFields: (nameList?: NamePath[]) => Promise<any>;
42-
validate: (nameList?: NamePath[]) => Promise<any>;
42+
validate: (nameList?: NamePath[] | false) => Promise<any>;
4343
scrollToField: (name: NamePath, options?: ScrollOptions) => Promise<void>;
4444
}
4545

@@ -123,15 +123,21 @@ export interface FormProps {
123123
transformDateFunc?: (date: any) => string;
124124
colon?: boolean;
125125
}
126+
export type RenderOpts = {
127+
disabled: boolean;
128+
[key: string]: any;
129+
};
126130
export interface FormSchema {
127131
// Field name
128132
field: string;
133+
// Extra Fields name[]
134+
fields?: string[];
129135
// Event name triggered by internal value change, default change
130136
changeEvent?: string;
131137
// Variable name bound to v-model Default value
132138
valueField?: string;
133139
// Label name
134-
label: string | VNode;
140+
label?: string | VNode;
135141
// Auxiliary text
136142
subLabel?: string;
137143
// Help text on the right side of the text
@@ -175,6 +181,9 @@ export interface FormSchema {
175181
// 默认值
176182
defaultValue?: any;
177183

184+
// 额外默认值数组对象
185+
defaultValueObj?: { [key: string]: any };
186+
178187
// 是否自动处理与时间相关组件的默认值
179188
isHandleDateDefaultValue?: boolean;
180189

@@ -188,13 +197,19 @@ export interface FormSchema {
188197
show?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean);
189198

190199
// Render the content in the form-item tag
191-
render?: (renderCallbackParams: RenderCallbackParams) => VNode | VNode[] | string;
200+
render?: (
201+
renderCallbackParams: RenderCallbackParams,
202+
opts: RenderOpts,
203+
) => VNode | VNode[] | string;
192204

193205
// Rendering col content requires outer wrapper form-item
194-
renderColContent?: (renderCallbackParams: RenderCallbackParams) => VNode | VNode[] | string;
206+
renderColContent?: (
207+
renderCallbackParams: RenderCallbackParams,
208+
opts: RenderOpts,
209+
) => VNode | VNode[] | string;
195210

196211
renderComponentContent?:
197-
| ((renderCallbackParams: RenderCallbackParams) => any)
212+
| ((renderCallbackParams: RenderCallbackParams, opts: RenderOpts) => any)
198213
| VNode
199214
| VNode[]
200215
| string;

src/utils/helper/tsxHelper.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { Slots } from 'vue';
22
import { isFunction } from '/@/utils/is';
3+
import { RenderOpts } from '/@/components/Form';
34

45
/**
56
* @description: Get slot to prevent empty error
67
*/
7-
export function getSlot(slots: Slots, slot = 'default', data?: any) {
8+
export function getSlot(slots: Slots, slot = 'default', data?: any, opts?: RenderOpts) {
89
if (!slots || !Reflect.has(slots, slot)) {
910
return null;
1011
}
@@ -14,7 +15,8 @@ export function getSlot(slots: Slots, slot = 'default', data?: any) {
1415
}
1516
const slotFn = slots[slot];
1617
if (!slotFn) return null;
17-
return slotFn(data);
18+
const params = { ...data, ...opts };
19+
return slotFn(params);
1820
}
1921

2022
/**

0 commit comments

Comments
 (0)