Commit 1d45617e4a311e339eb008a629cd342cd673ecf1

Authored by vben
1 parent 3f78b5aa

refactor(form): enhanced form customization and dynamic capabilities

CHANGELOG.zh_CN.md
@@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
4 4
5 - 重构 hook,引入 `@vueuse`,删除其中已有的`hook`,优化现有的 hook 5 - 重构 hook,引入 `@vueuse`,删除其中已有的`hook`,优化现有的 hook
6 - `useEvent` 更名->`useEventListener` 6 - `useEvent` 更名->`useEventListener`
  7 +- 表单`ComponentType`删除 `SelectOptGroup`,`SelectOption`,`Transfer`,`Radio`,四个类型。修改`RadioButtonGroup`组件
7 8
8 ### ✨ Features 9 ### ✨ Features
9 10
@@ -12,10 +13,15 @@ @@ -12,10 +13,15 @@
12 - 新增菜单及顶栏颜色选择配色 13 - 新增菜单及顶栏颜色选择配色
13 - 增加示例结果页 14 - 增加示例结果页
14 15
  16 +### ⚡ Wip
  17 +
  18 +- 上传组件(未完成,测试中...)
  19 +
15 ### ⚡ Performance Improvements 20 ### ⚡ Performance Improvements
16 21
17 - 优化 settingDrawer 代码 22 - 优化 settingDrawer 代码
18 - 优化多标签页切换速度 23 - 优化多标签页切换速度
  24 +- 增加表单自定义及动态能力
19 25
20 ### 🐛 Bug Fixes 26 ### 🐛 Bug Fixes
21 27
@@ -23,6 +29,7 @@ @@ -23,6 +29,7 @@
23 - 修复登录过期后重新登录未跳转原来页面的 29 - 修复登录过期后重新登录未跳转原来页面的
24 - 修复 window 系统动态引入错误 30 - 修复 window 系统动态引入错误
25 - 修复页面类型错误 31 - 修复页面类型错误
  32 +- 修复表单 switch 和 checkBox 单独使用报错
26 33
27 ## 2.0.0-rc.9 (2020-11-9) 34 ## 2.0.0-rc.9 (2020-11-9)
28 35
src/components/Form/src/BasicForm.vue
@@ -5,6 +5,7 @@ @@ -5,6 +5,7 @@
5 <template v-for="schema in getSchema" :key="schema.field"> 5 <template v-for="schema in getSchema" :key="schema.field">
6 <FormItem 6 <FormItem
7 :tableAction="tableAction" 7 :tableAction="tableAction"
  8 + :formActionType="formActionType"
8 :schema="schema" 9 :schema="schema"
9 :formProps="getProps" 10 :formProps="getProps"
10 :allDefaultValues="defaultValueRef" 11 :allDefaultValues="defaultValueRef"
@@ -164,7 +165,7 @@ @@ -164,7 +165,7 @@
164 propsRef.value = mergeProps; 165 propsRef.value = mergeProps;
165 } 166 }
166 167
167 - const methods: Partial<FormActionType> = { 168 + const formActionType: Partial<FormActionType> = {
168 getFieldsValue, 169 getFieldsValue,
169 setFieldsValue, 170 setFieldsValue,
170 resetFields, 171 resetFields,
@@ -179,7 +180,7 @@ @@ -179,7 +180,7 @@
179 180
180 onMounted(() => { 181 onMounted(() => {
181 initDefault(); 182 initDefault();
182 - emit('register', methods); 183 + emit('register', formActionType);
183 }); 184 });
184 185
185 return { 186 return {
@@ -191,7 +192,8 @@ @@ -191,7 +192,8 @@
191 getProps, 192 getProps,
192 formElRef, 193 formElRef,
193 getSchema, 194 getSchema,
194 - ...methods, 195 + formActionType,
  196 + ...formActionType,
195 }; 197 };
196 }, 198 },
197 }); 199 });
src/components/Form/src/FormItem.tsx
1 import type { PropType } from 'vue'; 1 import type { PropType } from 'vue';
2 -import type { FormProps } from './types/form'; 2 +import type { FormActionType, FormProps } from './types/form';
3 import type { FormSchema } from './types/form'; 3 import type { FormSchema } from './types/form';
4 import type { ValidationRule } from 'ant-design-vue/lib/form/Form'; 4 import type { ValidationRule } from 'ant-design-vue/lib/form/Form';
5 import type { TableActionType } from '/@/components/Table'; 5 import type { TableActionType } from '/@/components/Table';
@@ -41,6 +41,9 @@ export default defineComponent({ @@ -41,6 +41,9 @@ export default defineComponent({
41 tableAction: { 41 tableAction: {
42 type: Object as PropType<TableActionType>, 42 type: Object as PropType<TableActionType>,
43 }, 43 },
  44 + formActionType: {
  45 + type: Object as PropType<FormActionType>,
  46 + },
44 }, 47 },
45 setup(props, { slots }) { 48 setup(props, { slots }) {
46 const itemLabelWidthRef = useItemLabelWidth(toRef(props, 'schema'), toRef(props, 'formProps')); 49 const itemLabelWidthRef = useItemLabelWidth(toRef(props, 'schema'), toRef(props, 'formProps'));
@@ -61,12 +64,12 @@ export default defineComponent({ @@ -61,12 +64,12 @@ export default defineComponent({
61 }); 64 });
62 65
63 const getComponentsPropsRef = computed(() => { 66 const getComponentsPropsRef = computed(() => {
64 - const { schema, tableAction, formModel } = props; 67 + const { schema, tableAction, formModel, formActionType } = props;
65 const { componentProps = {} } = schema; 68 const { componentProps = {} } = schema;
66 if (!isFunction(componentProps)) { 69 if (!isFunction(componentProps)) {
67 return componentProps; 70 return componentProps;
68 } 71 }
69 - return componentProps({ schema, tableAction, formModel }) || {}; 72 + return componentProps({ schema, tableAction, formModel, formActionType }) || {};
70 }); 73 });
71 74
72 const getDisableRef = computed(() => { 75 const getDisableRef = computed(() => {
@@ -179,17 +182,27 @@ export default defineComponent({ @@ -179,17 +182,27 @@ export default defineComponent({
179 } 182 }
180 183
181 function renderComponent() { 184 function renderComponent() {
182 - const { renderComponentContent, component, field, changeEvent = 'change' } = props.schema; 185 + const {
  186 + renderComponentContent,
  187 + component,
  188 + field,
  189 + changeEvent = 'change',
  190 + valueField,
  191 + } = props.schema;
183 192
184 - const isCheck = component && ['Switch'].includes(component); 193 + const isCheck = component && ['Switch', 'Checkbox'].includes(component);
185 194
186 const eventKey = `on${upperFirst(changeEvent)}`; 195 const eventKey = `on${upperFirst(changeEvent)}`;
  196 +
187 const on = { 197 const on = {
188 [eventKey]: (e: any) => { 198 [eventKey]: (e: any) => {
189 if (propsData[eventKey]) { 199 if (propsData[eventKey]) {
190 propsData[eventKey](e); 200 propsData[eventKey](e);
191 } 201 }
192 - (props.formModel as any)[field] = e && e.target ? e.target.value : e; 202 +
  203 + const target = e ? e.target : null;
  204 + const value = target ? (isCheck ? target.checked : target.value) : e;
  205 + (props.formModel as any)[field] = value;
193 }, 206 },
194 }; 207 };
195 const Comp = componentMap.get(component); 208 const Comp = componentMap.get(component);
@@ -215,17 +228,20 @@ export default defineComponent({ @@ -215,17 +228,20 @@ export default defineComponent({
215 propsData.codeField = field; 228 propsData.codeField = field;
216 propsData.formValues = unref(getValuesRef); 229 propsData.formValues = unref(getValuesRef);
217 const bindValue = { 230 const bindValue = {
218 - [isCheck ? 'checked' : 'value']: handleValue(component, field), 231 + [valueField || (isCheck ? 'checked' : 'value')]: handleValue(component, field),
219 }; 232 };
220 if (!renderComponentContent) { 233 if (!renderComponentContent) {
221 return <Comp {...propsData} {...on} {...bindValue} />; 234 return <Comp {...propsData} {...on} {...bindValue} />;
222 } 235 }
  236 + const compSlot = isFunction(renderComponentContent)
  237 + ? { ...renderComponentContent(unref(getValuesRef)) }
  238 + : {
  239 + default: () => renderComponentContent,
  240 + };
223 241
224 return ( 242 return (
225 <Comp {...propsData} {...on} {...bindValue}> 243 <Comp {...propsData} {...on} {...bindValue}>
226 - {{  
227 - ...renderComponentContent(unref(getValuesRef)),  
228 - }} 244 + {compSlot}
229 </Comp> 245 </Comp>
230 ); 246 );
231 } 247 }
@@ -249,7 +265,7 @@ export default defineComponent({ @@ -249,7 +265,7 @@ export default defineComponent({
249 const { colon } = props.formProps; 265 const { colon } = props.formProps;
250 const getContent = () => { 266 const getContent = () => {
251 return slot 267 return slot
252 - ? getSlot(slots, slot) 268 + ? getSlot(slots, slot, unref(getValuesRef))
253 : render 269 : render
254 ? render(unref(getValuesRef)) 270 ? render(unref(getValuesRef))
255 : renderComponent(); 271 : renderComponent();
@@ -276,7 +292,7 @@ export default defineComponent({ @@ -276,7 +292,7 @@ export default defineComponent({
276 const { isIfShow, isShow } = getShow(); 292 const { isIfShow, isShow } = getShow();
277 const getContent = () => { 293 const getContent = () => {
278 return colSlot 294 return colSlot
279 - ? getSlot(slots, colSlot) 295 + ? getSlot(slots, colSlot, unref(getValuesRef))
280 : renderColContent 296 : renderColContent
281 ? renderColContent(unref(getValuesRef)) 297 ? renderColContent(unref(getValuesRef))
282 : renderItem(); 298 : renderItem();
src/components/Form/src/componentMap.ts
@@ -14,8 +14,8 @@ import { @@ -14,8 +14,8 @@ import {
14 Switch, 14 Switch,
15 TimePicker, 15 TimePicker,
16 TreeSelect, 16 TreeSelect,
17 - Transfer,  
18 } from 'ant-design-vue'; 17 } from 'ant-design-vue';
  18 +import RadioButtonGroup from './components/RadioButtonGroup.vue';
19 19
20 import { ComponentType } from './types/index'; 20 import { ComponentType } from './types/index';
21 21
@@ -30,13 +30,13 @@ componentMap.set(&#39;InputNumber&#39;, InputNumber); @@ -30,13 +30,13 @@ componentMap.set(&#39;InputNumber&#39;, InputNumber);
30 componentMap.set('AutoComplete', AutoComplete); 30 componentMap.set('AutoComplete', AutoComplete);
31 31
32 componentMap.set('Select', Select); 32 componentMap.set('Select', Select);
33 -componentMap.set('SelectOptGroup', Select.OptGroup);  
34 -componentMap.set('SelectOption', Select.Option); 33 +// componentMap.set('SelectOptGroup', Select.OptGroup);
  34 +// componentMap.set('SelectOption', Select.Option);
35 componentMap.set('TreeSelect', TreeSelect); 35 componentMap.set('TreeSelect', TreeSelect);
36 -componentMap.set('Transfer', Transfer);  
37 -componentMap.set('Radio', Radio); 36 +// componentMap.set('Transfer', Transfer);
  37 +// componentMap.set('Radio', Radio);
38 componentMap.set('Switch', Switch); 38 componentMap.set('Switch', Switch);
39 -componentMap.set('RadioButton', Radio.Button); 39 +componentMap.set('RadioButtonGroup', RadioButtonGroup);
40 componentMap.set('RadioGroup', Radio.Group); 40 componentMap.set('RadioGroup', Radio.Group);
41 componentMap.set('Checkbox', Checkbox); 41 componentMap.set('Checkbox', Checkbox);
42 componentMap.set('CheckboxGroup', Checkbox.Group); 42 componentMap.set('CheckboxGroup', Checkbox.Group);
src/components/Form/src/components/RadioButtonGroup.vue 0 → 100644
  1 +<template>
  2 + <RadioGroup v-bind="$attrs" v-model:value="valueRef" button-style="solid">
  3 + <template v-for="item in getOptions" :key="`${item.value}`">
  4 + <RadioButton :value="item.value"> {{ item.label }} </RadioButton>
  5 + </template>
  6 + </RadioGroup>
  7 +</template>
  8 +<script lang="ts">
  9 + import { defineComponent, ref, PropType, watch, unref, computed } from 'vue';
  10 + import { Radio } from 'ant-design-vue';
  11 + import {} from 'ant-design-vue/es/radio/Group';
  12 + import { isString } from '/@/utils/is';
  13 +
  14 + type OptionsItem = { label: string; value: string; disabled?: boolean };
  15 + type RadioItem = string | OptionsItem;
  16 + export default defineComponent({
  17 + name: 'RadioButtonGroup',
  18 + components: {
  19 + RadioGroup: Radio.Group,
  20 + RadioButton: Radio.Button,
  21 + },
  22 + props: {
  23 + value: {
  24 + type: String as PropType<string>,
  25 + },
  26 + options: {
  27 + type: Array as PropType<RadioItem[]>,
  28 + default: () => [],
  29 + },
  30 + },
  31 + setup(props, { emit }) {
  32 + const valueRef = ref('');
  33 +
  34 + watch(
  35 + () => props.value,
  36 + (v = '') => {
  37 + valueRef.value = v;
  38 + },
  39 + { immediate: true }
  40 + );
  41 +
  42 + watch(
  43 + () => unref(valueRef),
  44 + () => {
  45 + emit('change', valueRef.value);
  46 + },
  47 + { immediate: true }
  48 + );
  49 +
  50 + const getOptions = computed((): OptionsItem[] => {
  51 + const { options } = props;
  52 + if (!options || options.length === 0) return [];
  53 + const isStringArr = options.some((item) => isString(item));
  54 + if (!isStringArr) return options as OptionsItem[];
  55 + return options.map((item) => ({ label: item, value: item })) as OptionsItem[];
  56 + });
  57 +
  58 + return { valueRef, getOptions };
  59 + },
  60 + });
  61 +</script>
src/components/Form/src/types/form.ts
@@ -7,6 +7,10 @@ import { TableActionType } from &#39;../../../Table/src/types/table&#39;; @@ -7,6 +7,10 @@ import { TableActionType } from &#39;../../../Table/src/types/table&#39;;
7 7
8 export type FieldMapToTime = [string, [string, string], string?][]; 8 export type FieldMapToTime = [string, [string, string], string?][];
9 9
  10 +export type Rule = RuleObject & {
  11 + trigger?: 'blur' | 'change' | ['change', 'blur'];
  12 +};
  13 +
10 export interface RenderCallbackParams { 14 export interface RenderCallbackParams {
11 schema: FormSchema; 15 schema: FormSchema;
12 values: any; 16 values: any;
@@ -98,7 +102,10 @@ export interface FormProps { @@ -98,7 +102,10 @@ export interface FormProps {
98 export interface FormSchema { 102 export interface FormSchema {
99 // 字段名 103 // 字段名
100 field: string; 104 field: string;
  105 + // 内部值更改触发的事件名,默认 change
101 changeEvent?: string; 106 changeEvent?: string;
  107 + // v-model绑定的变量名 默认 value
  108 + valueField?: string;
102 // 标签名 109 // 标签名
103 label: string; 110 label: string;
104 // 文本右侧帮助文本 111 // 文本右侧帮助文本
@@ -113,13 +120,18 @@ export interface FormSchema { @@ -113,13 +120,18 @@ export interface FormSchema {
113 component: ComponentType; 120 component: ComponentType;
114 // 组件参数 121 // 组件参数
115 componentProps?: 122 componentProps?:
116 - | ((opt: { schema: FormSchema; tableAction: TableActionType; formModel: any }) => any) 123 + | ((opt: {
  124 + schema: FormSchema;
  125 + tableAction: TableActionType;
  126 + formActionType: FormActionType;
  127 + formModel: any;
  128 + }) => any)
117 | object; 129 | object;
118 // 必填 130 // 必填
119 required?: boolean; 131 required?: boolean;
120 132
121 // 校验规则 133 // 校验规则
122 - rules?: RuleObject[]; 134 + rules?: Rule[];
123 // 校验信息是否加入label 135 // 校验信息是否加入label
124 rulesMessageJoinLabel?: boolean; 136 rulesMessageJoinLabel?: boolean;
125 137
@@ -146,7 +158,11 @@ export interface FormSchema { @@ -146,7 +158,11 @@ export interface FormSchema {
146 // 渲染 col内容,需要外层包裹 form-item 158 // 渲染 col内容,需要外层包裹 form-item
147 renderColContent?: (renderCallbackParams: RenderCallbackParams) => VNode | VNode[] | string; 159 renderColContent?: (renderCallbackParams: RenderCallbackParams) => VNode | VNode[] | string;
148 160
149 - renderComponentContent?: (renderCallbackParams: RenderCallbackParams) => any; 161 + renderComponentContent?:
  162 + | ((renderCallbackParams: RenderCallbackParams) => any)
  163 + | VNode
  164 + | VNode[]
  165 + | string;
150 166
151 // 自定义slot, 在 from-item内 167 // 自定义slot, 在 from-item内
152 slot?: string; 168 slot?: string;
@@ -156,7 +172,7 @@ export interface FormSchema { @@ -156,7 +172,7 @@ export interface FormSchema {
156 172
157 dynamicDisabled?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean); 173 dynamicDisabled?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean);
158 174
159 - dynamicRules?: (renderCallbackParams: RenderCallbackParams) => RuleObject[]; 175 + dynamicRules?: (renderCallbackParams: RenderCallbackParams) => Rule[];
160 } 176 }
161 export interface HelpComponentProps { 177 export interface HelpComponentProps {
162 maxWidth: string; 178 maxWidth: string;
src/components/Form/src/types/index.ts
@@ -93,8 +93,8 @@ export type ComponentType = @@ -93,8 +93,8 @@ export type ComponentType =
93 | 'SelectOption' 93 | 'SelectOption'
94 | 'TreeSelect' 94 | 'TreeSelect'
95 | 'Transfer' 95 | 'Transfer'
96 - | 'Radio'  
97 - | 'RadioButton' 96 + // | 'Radio'
  97 + | 'RadioButtonGroup'
98 | 'RadioGroup' 98 | 'RadioGroup'
99 | 'Checkbox' 99 | 'Checkbox'
100 | 'CheckboxGroup' 100 | 'CheckboxGroup'
src/components/Table/src/types/table.ts
@@ -87,7 +87,7 @@ export interface GetColumnsParams { @@ -87,7 +87,7 @@ export interface GetColumnsParams {
87 export type SizeType = 'default' | 'middle' | 'small' | 'large'; 87 export type SizeType = 'default' | 'middle' | 'small' | 'large';
88 88
89 export interface TableActionType { 89 export interface TableActionType {
90 - reload: (opt?: FetchParams) => Promise<void>; 90 + // reload: (opt?: FetchParams) => Promise<void>;
91 getSelectRows: () => any[]; 91 getSelectRows: () => any[];
92 clearSelectedRowKeys: () => void; 92 clearSelectedRowKeys: () => void;
93 getSelectRowKeys: () => string[]; 93 getSelectRowKeys: () => string[];
src/router/menus/modules/demo/comp.ts
@@ -38,10 +38,10 @@ const menu: MenuModule = { @@ -38,10 +38,10 @@ const menu: MenuModule = {
38 path: 'strength-meter', 38 path: 'strength-meter',
39 name: '密码强度组件', 39 name: '密码强度组件',
40 }, 40 },
41 - {  
42 - path: 'upload',  
43 - name: '上传组件',  
44 - }, 41 + // {
  42 + // path: 'upload',
  43 + // name: '上传组件',
  44 + // },
45 { 45 {
46 path: 'scroll', 46 path: 'scroll',
47 name: '滚动组件', 47 name: '滚动组件',
src/router/menus/modules/demo/form.ts
@@ -4,10 +4,18 @@ const menu: MenuModule = { @@ -4,10 +4,18 @@ const menu: MenuModule = {
4 menu: { 4 menu: {
5 path: '/form', 5 path: '/form',
6 name: 'Form', 6 name: 'Form',
  7 + tag: {
  8 + type: 'warn',
  9 + dot: true,
  10 + },
7 children: [ 11 children: [
8 { 12 {
9 path: 'basic', 13 path: 'basic',
10 name: '基础表单', 14 name: '基础表单',
  15 + tag: {
  16 + type: 'warn',
  17 + content: 'updated',
  18 + },
11 }, 19 },
12 { 20 {
13 path: 'useForm', 21 path: 'useForm',
@@ -24,14 +32,26 @@ const menu: MenuModule = { @@ -24,14 +32,26 @@ const menu: MenuModule = {
24 { 32 {
25 path: 'ruleForm', 33 path: 'ruleForm',
26 name: '表单校验', 34 name: '表单校验',
  35 + tag: {
  36 + type: 'warn',
  37 + content: 'updated',
  38 + },
27 }, 39 },
28 { 40 {
29 path: 'dynamicForm', 41 path: 'dynamicForm',
30 name: '动态表单', 42 name: '动态表单',
  43 + tag: {
  44 + type: 'warn',
  45 + content: 'updated',
  46 + },
31 }, 47 },
32 { 48 {
33 path: 'customerForm', 49 path: 'customerForm',
34 name: '自定义组件', 50 name: '自定义组件',
  51 + tag: {
  52 + type: 'warn',
  53 + content: 'updated',
  54 + },
35 }, 55 },
36 ], 56 ],
37 }, 57 },
src/views/demo/form/CustomerForm.vue
1 <template> 1 <template>
2 <div class="m-4"> 2 <div class="m-4">
3 <CollapseContainer title="自定义表单"> 3 <CollapseContainer title="自定义表单">
4 - <BasicForm @register="register" @submit="handleSubmit" /> 4 + <BasicForm @register="register" @submit="handleSubmit">
  5 + <template #f3="{ model, field }">
  6 + <a-input v-model:value="model[field]" placeholder="自定义slot" />
  7 + </template>
  8 + </BasicForm>
5 </CollapseContainer> 9 </CollapseContainer>
6 </div> 10 </div>
7 </template> 11 </template>
@@ -15,7 +19,7 @@ @@ -15,7 +19,7 @@
15 { 19 {
16 field: 'field1', 20 field: 'field1',
17 component: 'Input', 21 component: 'Input',
18 - label: '字段1', 22 + label: 'render方式',
19 colProps: { 23 colProps: {
20 span: 8, 24 span: 8,
21 }, 25 },
@@ -33,7 +37,7 @@ @@ -33,7 +37,7 @@
33 { 37 {
34 field: 'field2', 38 field: 'field2',
35 component: 'Input', 39 component: 'Input',
36 - label: '字段2', 40 + label: 'render组件slot',
37 colProps: { 41 colProps: {
38 span: 8, 42 span: 8,
39 }, 43 },
@@ -44,6 +48,16 @@ @@ -44,6 +48,16 @@
44 }; 48 };
45 }, 49 },
46 }, 50 },
  51 + {
  52 + field: 'field3',
  53 + component: 'Input',
  54 + label: '自定义Slot',
  55 + slot: 'f3',
  56 + colProps: {
  57 + span: 8,
  58 + },
  59 + rules: [{ required: true }],
  60 + },
47 ]; 61 ];
48 export default defineComponent({ 62 export default defineComponent({
49 components: { BasicForm, CollapseContainer }, 63 components: { BasicForm, CollapseContainer },
src/views/demo/form/DynamicForm.vue
@@ -9,6 +9,10 @@ @@ -9,6 +9,10 @@
9 <CollapseContainer title="动态表单示例,动态根据表单内其他值改变"> 9 <CollapseContainer title="动态表单示例,动态根据表单内其他值改变">
10 <BasicForm @register="register" /> 10 <BasicForm @register="register" />
11 </CollapseContainer> 11 </CollapseContainer>
  12 +
  13 + <CollapseContainer class="mt-5" title="componentProps动态改变">
  14 + <BasicForm @register="register1" />
  15 + </CollapseContainer>
12 </div> 16 </div>
13 </template> 17 </template>
14 <script lang="ts"> 18 <script lang="ts">
@@ -120,6 +124,58 @@ @@ -120,6 +124,58 @@
120 }, 124 },
121 ]; 125 ];
122 126
  127 + const schemas1: FormSchema[] = [
  128 + {
  129 + field: 'f1',
  130 + component: 'Input',
  131 + label: 'F1',
  132 + colProps: {
  133 + span: 12,
  134 + },
  135 + labelWidth: 200,
  136 + componentProps: ({ formModel }) => {
  137 + return {
  138 + placeholder: '同步f2的值为f1',
  139 + onChange: (e: ChangeEvent) => {
  140 + formModel.f2 = e.target.value;
  141 + },
  142 + };
  143 + },
  144 + },
  145 + {
  146 + field: 'f2',
  147 + component: 'Input',
  148 + label: 'F2',
  149 + colProps: {
  150 + span: 12,
  151 + },
  152 + labelWidth: 200,
  153 + componentProps: { disabled: true },
  154 + },
  155 + {
  156 + field: 'f3',
  157 + component: 'Input',
  158 + label: 'F3',
  159 + colProps: {
  160 + span: 12,
  161 + },
  162 + labelWidth: 200,
  163 + // @ts-ignore
  164 + componentProps: ({ formActionType, tableAction }) => {
  165 + return {
  166 + placeholder: '值改变时执行查询,查看控制台',
  167 + onChange: async () => {
  168 + const { validate } = formActionType;
  169 + // tableAction只适用于在表格内开启表单的例子
  170 + // const { reload } = tableAction;
  171 + const res = await validate();
  172 + console.log(res);
  173 + },
  174 + };
  175 + },
  176 + },
  177 + ];
  178 +
123 export default defineComponent({ 179 export default defineComponent({
124 components: { BasicForm, CollapseContainer }, 180 components: { BasicForm, CollapseContainer },
125 setup() { 181 setup() {
@@ -133,6 +189,13 @@ @@ -133,6 +189,13 @@
133 span: 24, 189 span: 24,
134 }, 190 },
135 }); 191 });
  192 + const [register1] = useForm({
  193 + labelWidth: 120,
  194 + schemas: schemas1,
  195 + actionColOptions: {
  196 + span: 24,
  197 + },
  198 + });
136 function changeLabel3() { 199 function changeLabel3() {
137 updateSchema({ 200 updateSchema({
138 field: 'field3', 201 field: 'field3',
@@ -170,6 +233,7 @@ @@ -170,6 +233,7 @@
170 } 233 }
171 return { 234 return {
172 register, 235 register,
  236 + register1,
173 schemas, 237 schemas,
174 setProps, 238 setProps,
175 changeLabel3, 239 changeLabel3,
src/views/demo/form/RuleForm.vue
@@ -65,7 +65,33 @@ @@ -65,7 +65,33 @@
65 }, 65 },
66 ], 66 ],
67 }, 67 },
68 - rules: [{ required: true, message: '请输入aa' }], 68 + rules: [
  69 + {
  70 + required: true,
  71 + message: '请输入aa',
  72 + },
  73 + ],
  74 + },
  75 + {
  76 + field: 'field44',
  77 + component: 'Input',
  78 + label: '自定义校验',
  79 + colProps: {
  80 + span: 8,
  81 + },
  82 + rules: [
  83 + {
  84 + required: true,
  85 + // @ts-ignore
  86 + validator: async (rule, value) => {
  87 + if (value === '1') {
  88 + return Promise.reject('值不能为1');
  89 + }
  90 + return Promise.resolve();
  91 + },
  92 + trigger: 'blur',
  93 + },
  94 + ],
69 }, 95 },
70 { 96 {
71 field: 'field5', 97 field: 'field5',
src/views/demo/form/index.vue
@@ -11,10 +11,11 @@ @@ -11,10 +11,11 @@
11 </div> 11 </div>
12 </template> 12 </template>
13 <script lang="ts"> 13 <script lang="ts">
14 - import { defineComponent } from 'vue'; 14 + import { defineComponent, ref } from 'vue';
15 import { BasicForm, FormSchema } from '/@/components/Form/index'; 15 import { BasicForm, FormSchema } from '/@/components/Form/index';
16 import { CollapseContainer } from '/@/components/Container/index'; 16 import { CollapseContainer } from '/@/components/Container/index';
17 import { useMessage } from '/@/hooks/web/useMessage'; 17 import { useMessage } from '/@/hooks/web/useMessage';
  18 +
18 const schemas: FormSchema[] = [ 19 const schemas: FormSchema[] = [
19 { 20 {
20 field: 'field1', 21 field: 'field1',
@@ -23,8 +24,11 @@ @@ -23,8 +24,11 @@
23 colProps: { 24 colProps: {
24 span: 8, 25 span: 8,
25 }, 26 },
26 - defaultValue: '111',  
27 - componentProps: () => { 27 + // componentProps:{},
  28 + // can func
  29 + componentProps: ({ schema, formModel }) => {
  30 + console.log('form:', schema);
  31 + console.log('formModel:', formModel);
28 return { 32 return {
29 placeholder: '自定义placeholder', 33 placeholder: '自定义placeholder',
30 onChange: (e: any) => { 34 onChange: (e: any) => {
@@ -32,14 +36,26 @@ @@ -32,14 +36,26 @@
32 }, 36 },
33 }; 37 };
34 }, 38 },
  39 + renderComponentContent: () => {
  40 + return {
  41 + prefix: () => 'pSlot',
  42 + suffix: () => 'sSlot',
  43 + };
  44 + },
35 }, 45 },
36 { 46 {
37 field: 'field2', 47 field: 'field2',
38 component: 'Input', 48 component: 'Input',
39 label: '字段2', 49 label: '字段2',
  50 + defaultValue: '111',
40 colProps: { 51 colProps: {
41 span: 8, 52 span: 8,
42 }, 53 },
  54 + componentProps: {
  55 + onChange: (e: any) => {
  56 + console.log(e);
  57 + },
  58 + },
43 }, 59 },
44 { 60 {
45 field: 'field3', 61 field: 'field3',
@@ -111,17 +127,100 @@ @@ -111,17 +127,100 @@
111 ], 127 ],
112 }, 128 },
113 }, 129 },
  130 + {
  131 + field: 'field8',
  132 + component: 'Checkbox',
  133 + label: '字段8',
  134 + colProps: {
  135 + span: 8,
  136 + },
  137 + renderComponentContent: 'Check',
  138 + },
  139 + {
  140 + field: 'field9',
  141 + component: 'Switch',
  142 + label: '字段9',
  143 + colProps: {
  144 + span: 8,
  145 + },
  146 + },
  147 + {
  148 + field: 'field10',
  149 + component: 'RadioButtonGroup',
  150 + label: '字段10',
  151 + colProps: {
  152 + span: 8,
  153 + },
  154 + componentProps: {
  155 + options: [
  156 + {
  157 + label: '选项1',
  158 + value: '1',
  159 + },
  160 + {
  161 + label: '选项2',
  162 + value: '2',
  163 + },
  164 + ],
  165 + },
  166 + },
  167 + {
  168 + field: 'field11',
  169 + component: 'Cascader',
  170 + label: '字段11',
  171 + colProps: {
  172 + span: 8,
  173 + },
  174 + componentProps: {
  175 + options: [
  176 + {
  177 + value: 'zhejiang',
  178 + label: 'Zhejiang',
  179 + children: [
  180 + {
  181 + value: 'hangzhou',
  182 + label: 'Hangzhou',
  183 + children: [
  184 + {
  185 + value: 'xihu',
  186 + label: 'West Lake',
  187 + },
  188 + ],
  189 + },
  190 + ],
  191 + },
  192 + {
  193 + value: 'jiangsu',
  194 + label: 'Jiangsu',
  195 + children: [
  196 + {
  197 + value: 'nanjing',
  198 + label: 'Nanjing',
  199 + children: [
  200 + {
  201 + value: 'zhonghuamen',
  202 + label: 'Zhong Hua Men',
  203 + },
  204 + ],
  205 + },
  206 + ],
  207 + },
  208 + ],
  209 + },
  210 + },
114 ]; 211 ];
115 212
116 export default defineComponent({ 213 export default defineComponent({
117 components: { BasicForm, CollapseContainer }, 214 components: { BasicForm, CollapseContainer },
118 setup() { 215 setup() {
  216 + const check = ref(null);
119 const { createMessage } = useMessage(); 217 const { createMessage } = useMessage();
120 return { 218 return {
121 schemas, 219 schemas,
122 handleSubmit: (values: any) => { 220 handleSubmit: (values: any) => {
123 createMessage.success('click search,values:' + JSON.stringify(values)); 221 createMessage.success('click search,values:' + JSON.stringify(values));
124 }, 222 },
  223 + check,
125 }; 224 };
126 }, 225 },
127 }); 226 });