BasicForm 表单组件、使用方法、属性列表、表单验证
# 介绍
对 Antdv 的 Form 表单 (opens new window) 组件进行封装,通过非常便捷的配置完成表单渲染和表单验证。
请勿觉着 BasicForm 封装的太多,其实非常灵活,就像 Table 一样,只需编写 JS 即可渲染整个表单,其中:事件、属性、自定义、异步完全没有问题,复杂任意场景都可以通过“插槽”自定义,没有不能实现的表单。如果您的表单很大,可以异步加载,编写多个 BasicForm 或分多个 vue 组件,不存在任何性能瓶颈。您用起来试下,您就会爱上她。
v5.1.0 及之前版本:Antdv 2.x Form 表单 (opens new window)
# 使用
# 最简单示例
展示一个最简单表单的示例,只有一个输入框
<template>
<div class="m-4">
<BasicForm
:labelWidth="100"
:schemas="schemas"
:showActionButtonGroup="true"
:submitButtonOptions="{ text: '提交' }"
:actionColOptions="{ span: 5 }"
@submit="handleSubmit"
/>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { BasicForm, FormSchema } from '/@/components/Form';
import { useMessage } from '/@/hooks/web/useMessage';
const schemas: FormSchema[] = [
{
field: 'field',
component: 'Input',
label: '字段标签',
colProps: {
span: 8,
},
defaultValue: '123',
componentProps: {
placeholder: '这是一个输入框',
onChange: (e: ChangeEvent) => {
console.log('change', e);
},
},
},
];
export default defineComponent({
components: { BasicForm },
setup() {
const { createMessage } = useMessage();
return {
schemas,
handleSubmit: (values: any) => {
createMessage.success('表单值: ' + JSON.stringify(values));
},
};
},
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# useForm 示例
页面表单推荐使用方法,方便传值和调用内部方法。
<template>
<div class="m-4">
<BasicForm @register="register" @submit="handleSubmit" />
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
import { useMessage } from '/@/hooks/web/useMessage';
const schemas: FormSchema[] = [
{
field: 'field',
component: 'Input',
label: '字段标签',
colProps: {
span: 8,
},
defaultValue: '123',
componentProps: {
placeholder: '这是一个输入框',
onChange: (e: ChangeEvent) => {
console.log('change', e.target.value);
},
},
},
];
export default defineComponent({
components: { BasicForm },
setup() {
const { createMessage } = useMessage();
// 参数 props 内的值可以是 computed 或者 ref 类型
const [register, methods] = useForm({
labelWidth: 120,
schemas,
showActionButtonGroup: true,
submitButtonOptions: {
text: '提交',
},
actionColOptions: {
span: 5,
},
// 是否禁用表单所有控件
disabled: false,
});
return {
register,
schemas,
handleSubmit: (values: any) => {
// 更新字段值
values.field = '456';
methods.setFieldsValue(values);
// 获取字段值
const vals = methods.getFieldsValue();
createMessage.success('表单值: ' + JSON.stringify(vals));
},
};
},
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# register
register 用于注册 useForm
,如果需要使用 useForm
提供的 api,必须将 register 传入组件的 @register
<template>
<BasicForm @register="register" @submit="handleSubmit" />
</template>
<script>
export default defineComponent({
components: { BasicForm },
setup() {
const [register] = useForm();
return {
register,
};
},
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
# methods
getFieldsValue
类型: () => Recordable;
说明: 获取表单值
setFieldsValue
类型: <T>(values: T) => Promise<void>
说明: 设置表单字段值
resetFields
类型: ()=> Promise<any>
说明: 重置表单值
validateFields
类型: (nameList?: NamePath[]) => Promise<any>
说明: 校验指定表单项
validate
类型: (nameList?: NamePath[]) => Promise<any>
说明: 校验整个表单
submit
类型: () => Promise<void>
说明: 提交表单
scrollToField
类型: (name: NamePath, options?: ScrollOptions) => Promise<void>
说明: 滚动到对应字段位置
clearValidate
类型: (name?: string | string[]) => Promise<void>
说明: 清空校验
setProps
提示
设置表单的 props 可以直接在标签上传递,也可以使用 setProps,或者初始化直接写 useForm(props)
类型: (formProps: Partial<FormProps>) => Promise<void>
说明: 设置表单 Props
removeSchemaByFiled
类型: (field: string | string[]) => Promise<void>
说明: 根据 field 删除 Schema
appendSchemaByField
类型: ( schema: FormSchema, prefixField: string | undefined, first?: boolean | undefined ) => Promise<void>
说明: 插入到指定 filed 后面,如果没传指定 field,则插入到最后,当 first = true 时插入到第一个位置
updateSchema
类型: (data: Partial<FormSchema> | Partial<FormSchema>[]) => Promise<void>
说明: 更新表单的 schema, 只更新函数所传的参数
e.g
updateSchema({ field: 'filed', componentProps: { disabled: true } });
updateSchema([
{ field: 'filed', componentProps: { disabled: true } },
{ field: 'filed1', componentProps: { disabled: false } },
]);
2
3
4
5
# 属性
温馨提醒
除以下参数外,官方文档内的 props 也都支持,具体可以参考 Antdv Form 表单 (opens new window)
v5.1.0 及之前版本:Antdv 2.x Form 表单 (opens new window)
属性 | 类型 | 默认值 | 可选值 | 说明 |
---|---|---|---|---|
schemas | Schema[] | - | - | 表单配置,见下方 FormSchema 配置 |
submitOnReset | boolean | true | - | 重置时是否提交表单 |
labelCol | Partial<ColEx> | - | - | 整个表单通用 LabelCol 配置 |
wrapperCol | Partial<ColEx> | - | - | 整个表单通用 wrapperCol 配置 |
baseColProps | Partial<ColEx> | - | - | 配置所有选子项的 ColProps,不需要逐个配置,子项也可单独配置优先与全局 |
baseRowStyle | object | - | - | 配置所有 Row 的 style 样式 |
labelWidth | number , string | - | - | 扩展 form 组件,增加 label 宽度,表单内所有组件适用,可以单独在某个项覆盖或者禁用 |
labelAlign | string | - | left ,right | label 布局 |
mergeDynamicData | object | - | - | 额外传递到子组件的参数 values |
autoFocusFirstItem | boolean | false | - | 是否聚焦第一个输入框,只在第一个表单项为 input 的时候作用 |
compact | boolean | false | true/false | 紧凑类型表单,减少 margin-bottom |
size | string | default | 'default' , 'small' , 'large' | 向表单内所有组件传递 size 参数,自定义组件需自行实现 size 接收 |
disabled | boolean | false | true/false | 向表单内所有组件传递 disabled 属性,自定义组件需自行实现 disabled 接收 |
autoSetPlaceHolder | boolean | true | true/false | 自动设置表单内组件的 placeholder,自定义组件需自行实现 |
autoSubmitOnEnter | boolean | false | true/false | 在input中输入时按回车自动提交 |
rulesMessageJoinLabel | boolean | false | true/false | 如果表单项有校验,会自动生成校验信息,该参数控制是否将字段中文名字拼接到自动生成的信息后方 |
showAdvancedButton | boolean | false | true/false | 是否显示收起展开按钮 |
emptySpan | number , Partial<ColEx> | 0 | - | 空白行格,可以是数值或者 col 对象 数 |
autoAdvancedLine | number | 3 | - | 如果 showAdvancedButton 为 true,超过指定行数行默认折叠 |
alwaysShowLines | number | 1 | - | 折叠时始终保持显示的行数 |
showActionButtonGroup | boolean | true | true/false | 是否显示操作按钮(重置/提交) |
actionColOptions | Partial<ColEx> | - | - | 操作按钮外层 Col 组件配置,如果开启 showAdvancedButton,则不用设置,具体见下方 actionColOptions |
showResetButton | boolean | true | - | 是否显示重置按钮 |
resetButtonOptions | object | - | 重置按钮配置 ButtonProps (opens new window) | |
showSubmitButton | boolean | true | - | 是否显示提交按钮 |
submitButtonOptions | object | - | 确认按钮配置 ButtonProps (opens new window) | |
resetFunc | () => Promise<void> | - | 自定义重置按钮逻辑() => Promise<void>; | |
submitFunc | () => Promise<void> | - | 自定义提交按钮逻辑() => Promise<void>; | |
fieldMapToTime | [string, [string, string], string?][] | - | 用于将表单内时间区域的应设成 2 个字段,见下方说明 |
# ColEx 布局类型
常用属性:span、offset、plus、xs、sm、md、lg、xl、xxl
详细见 src/components/Form/src/types/index.ts (opens new window)
# fieldMapToTime 日期转换
将表单内时间区域的值映射成 2 个字段
如果表单内有时间区间组件,获取到的值是一个数组,但是往往我们传递到后台需要是 2 个字段
useForm({
fieldMapToTime: [
// data为时间组件在表单内的字段,startTime,endTime为转化后的开始时间于结束时间
// 'YYYY-MM-DD'为时间格式,参考moment
['datetime', ['startTime', 'endTime'], 'YYYY-MM-DD'],
// 支持多个字段
['datetime1', ['startTime1', 'endTime1'], 'YYYY-MM-DD HH:mm:ss'],
],
});
// fieldMapToTime没写的时候表单获取到的值
{
datetime: [Date(),Date()]
}
// ['datetime', ['startTime', 'endTime'], 'YYYY-MM-DD'],之后
{
datetime: [Date(),Date()],
startTime: '2020-08-12',
endTime: '2020-08-15',
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# FormSchema 控件设置
属性 | 类型 | 默认值 | 可选值 | 说明 |
---|---|---|---|---|
field | string | - | - | 字段名 |
fieldLabel | string | - | - | 字段标签名,如返回 Select、TreeSelect 的标签名 |
changeEvent | string | change | - | 表单更新事件名称 |
valueField | string | - | value | 绑定组件的属性名(一般无需设置)如:v-model:value |
labelField | string | - | labelValue | 绑定组件的标签属性名(一般无需设置)如:v-model:labelValue |
label | string | - | - | 标签名 |
subLabel | string | - | - | 二级标签名灰色 |
helpMessage | string , string[] | - | - | 标签名右侧温馨提示 |
helpComponentProps | HelpComponentProps | - | - | 标签名右侧温馨提示组件 props,见下方 HelpComponentProps |
labelWidth | string , number | - | - | 覆盖统一设置的 labelWidth |
disabledLabelWidth | boolean | false | true/false | 禁用 form 全局设置的 labelWidth,自己手动设置 labelCol 和 wrapperCol |
component | ComponentType | Input | - | 组件类型,见下方 ComponentType |
componentProps | any,()=>{} | - | - | 所渲染的组件的 props |
rules | ValidationRule[] | - | - | 校验规则,见下方 ValidationRule |
required | boolean | - | - | 简化 rules 配置,为 true 则转化成 [{required:true}]。2.4.0 之前的版本只支持string类型的值 |
suffix | string , number , ((values: RenderCallbackParams) => string / number); | - | - | 组件后面的内容 |
rulesMessageJoinLabel | boolean | false | - | 校验信息是否加入 label |
itemProps | any | - | - | 参考下方 FormItem |
colProps | ColEx | - | - | 参考上方 actionColOptions |
defaultValue | object | - | - | 所渲渲染组件的初始值 |
defaultLabel | object | - | - | 存储编码的显示名称初始值,如 treeCode 和 treeName |
isAdvanced | boolean | - | - | 是否显示表单,展开和收起按钮 |
render | (renderCallbackParams: RenderCallbackParams) => VNode / VNode[] / string | - | - | 自定义渲染组件 |
renderColContent | (renderCallbackParams: RenderCallbackParams) => VNode / VNode[] / string | - | - | 自定义渲染组件(需要自行包含 formItem) |
renderComponentContent | (renderCallbackParams: RenderCallbackParams) => any / string | - | - | 自定义渲染组内部的 slot |
slot | string | - | - | 自定义 slot,渲染组件 |
colSlot | string | - | - | 自定义 slot,渲染组件 (需要自行包含 formItem) |
show | boolean / ((renderCallbackParams: RenderCallbackParams) => boolean) | - | - | 动态判断当前组件是否显示,css 控制,不会删除 dom |
ifShow | boolean / ((renderCallbackParams: RenderCallbackParams) => boolean) | - | - | 动态判断当前组件是否显示,js 控制,会删除 dom |
dynamicDisabled | boolean / ((renderCallbackParams: RenderCallbackParams) => boolean) | - | - | 动态判断当前组件是否禁用 |
dynamicRules | boolean / ((renderCallbackParams: RenderCallbackParams) => boolean) | - | - | 动态判返当前组件您校验规则 |
RenderCallbackParams
export interface RenderCallbackParams {
schema: FormSchema;
values: any;
model: any;
field: string;
}
2
3
4
5
6
componentProps
当值为对象类型时,该对象将作为
component
所对应组件的的 props 传入组件当值为一个函数时候
参数有 4 个
schema
: 表单的整个 schemas
formActionType
: 操作表单的函数。与 useForm 返回的操作函数一致
formModel
: 表单的双向绑定对象,这个值是响应式的。所以可以方便处理很多操作
tableAction
: 操作表格的函数,与 useTable 返回的操作函数一致。注意该参数只在表格内开启搜索表单的时候有值,其余情况为null
,
HelpComponentProps
export interface HelpComponentProps {
maxWidth: string;
// 是否显示序号
showIndex: boolean;
// 文本列表
text: any;
// 颜色
color: string;
// 字体大小
fontSize: string;
icon: string;
absolute: boolean;
// 定位
position: any;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# ComponentType 组件类型
表单组件的组件类型 src/components/Form/src/componentMap.ts (opens new window)
export type ComponentType =
| 'Input'
| 'InputGroup'
| 'InputPassword'
| 'InputSearch'
| 'InputTextArea'
| 'InputNumber'
| 'InputCountDown'
| 'Select'
| 'TreeSelect'
| 'RadioButtonGroup'
| 'RadioGroup'
| 'Checkbox'
| 'CheckboxGroup'
| 'AutoComplete'
| 'Cascader'
| 'DatePicker'
| 'MonthPicker'
| 'RangePicker'
| 'WeekPicker'
| 'TimePicker'
| 'Switch'
| 'StrengthMeter'
| 'Upload'
| 'IconPicker'
| 'Render'
| 'Slider'
| 'Rate'
| 'None'
| 'Divider'
| 'FormGroup';
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
详细用法,可看本文:内置组件
# 表单插槽
# Slots
名称 | 说明 |
---|---|
formHeader | 表单顶部区域 |
formFooter | 表单底部区域 |
submitBefore | 提交按钮前 |
resetBefore | 重置按钮前 |
advanceBefore | 展开按钮前 |
advanceAfter | 展开按钮后 |
# Form-Slots
在在表格上方的查询表单使用插槽时,以 form-xxxx
为前缀的 slot 会被视为 form 的 slot,例如:
form-submitBefore
# 内置表单组件
# Select 下拉选择
在 Antdv 的 Select 选择器 (opens new window) 基础之上封装,支持:字典数据、远程API数据、单选或多选。
v5.1.0 及之前版本:Antdv 2.x Select 选择器 (opens new window)
# 使用
const schemas: FormSchema[] = [
{
label: '下拉框',
field: 'testSelect',
component: 'Select',
componentProps: {
// 数据源1:固定数据
options: [
{ label: '选项1', value: '11' },
{ label: '选项2', value: '22' },
],
// 数据源2:动态数据
// api: testDataSelectApi
// params: {},
// 数据源3:字典数据
// dictType: 'sys_menu_type',
allowClear: true,
mode: 'multiple', // 多选
},
},
];
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 属性
属性 | 类型 | 默认值 | 说明 |
---|---|---|---|
value | object | - | 控件值(双向绑定) |
labelValue | object | - | 控件值的标签,如 treeCode和treeName |
labelInValue | boolean | false | 是否同时返回 labelValue(双向绑定) |
options | OptionsItem[] | [] | 下拉框选项,不启用 api 的时候,固定值可以使用 |
api | ()=>Promise<{ label: string; value: string; disabled?: boolean }[]> | - | 数据接口,接受一个 Promise 对象 |
params | object | - | 接口参数。此属性改变时会自动重新加载接口数据 |
resultField | string | - | 接口返回的字段,如果接口返回数组,可以不填。支持x.x.x 格式 |
immediate | boolean | false | 是否立即请求接口,否则将在第一次点击时候触发请求 |
dictType | string | - | 字典类型的下拉框,设置字典类型 |
mode | boolean | true | 模式为多选或标签('multiple' |
其它属性:Antdv Select 属性 (opens new window) v5.1.0 及之前版本:Antdv 2.x Select 属性 (opens new window)
OptionsItem
属性 | 类型 | 默认值 | 说明 |
---|---|---|---|
label | object | - | 选项显示标签 |
value | object | - | 选项值 |
disabled | boolean | - | 是否禁止选择 |
# TreeSelect 下拉选择树
在 antdv 的 TreeSelect 选择器 (opens new window) 基础之上封装,支持:字典数据、远程API数据、单选或多选。
v5.1.0 及之前版本:Antdv 2.x TreeSelect 选择器 (opens new window)
# 使用
const schemas: FormSchema[] = [
{
label: '用户选择',
field: 'testUser.userCode',
fieldLabel: 'testUser.userName',
component: 'TreeSelect',
componentProps: {
// 数据源1:固定数据
treeDataSimpleMode: false,
treeData: [
{
id: '1',
name: 'tree 1',
disabled: true,
children: [
{ id: '1-1', name: 'tree 1-1' },
{ id: '1-2', name: 'tree 1-2' },
],
},
{
id: '2',
name: 'tree 2',
disabled: true,
children: [
{ id: '2-1', name: 'tree 2-1' },
{ id: '2-2', name: 'tree 2-2' },
],
},
],
// 数据源2:动态数据
// api: officeTreeData,
// params: { isLoadUser: true, userIdPrefix: '' },
// canSelectParent: false,
// 数据源3:字典数据
// dictType: 'sys_menu_type',
allowClear: true,
},
},
];
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 属性
属性 | 类型 | 默认值 | 说明 |
---|---|---|---|
value | object | - | 控件值(双向绑定) |
labelValue | object | - | 控件值的标签,如 treeCode和treeName |
labelInValue | boolean | false | 是否同时返回 labelValue(双向绑定) |
treeData | TreeDataItem[] | [] | 下拉框选项,不启用 api 的时候,固定值可以使用 |
api | ()=>Promise<{ id: string; name: string; pId: string; disabled?: boolean }[]> | - | 数据接口,接受一个 Promise 对象 |
params | object | - | 接口参数。此属性改变时会自动重新加载接口数据 |
resultField | string | - | 接口返回的字段,如果接口返回数组,可以不填。支持x.x.x 格式 |
immediate | boolean | false | 是否立即请求接口,否则将在第一次点击时候触发请求 |
dictType | string | - | 字典类型的下拉框,设置字典类型 |
treeCheckable | boolean | - | 是否多选 |
treeDataSimpleMode | boolean | true | 是否ztree格式 { id, pId, name } |
canSelectParent | boolean | true | 是否可以选择父级 |
其它属性:Antdv TreeSelect 属性 (opens new window) v5.1.0 及之前版本:Antdv 2.x TreeSelect 属性 (opens new window)
# ListSelect 列表选择树
列表选择,展现为可搜索的输入选择框,点击后弹出对话框,体现列表形式选择数据。
相比 TreeSelect 性能更好,支持大数据,异步加载组件和数据、单选或多选。
# 使用
const schemas: FormSchema[] = [
{
label: '列表选择',
field: 'customCode',
fieldLabel: 'customName',
component: 'ListSelect',
componentProps: {
// 内置列表选择类型:
// 1)userSelect:用户选择;
// 2)empUserSelect:员工选择(含组织机构信息)
// 3)自定义,详见下一节
selectType: 'userSelect',
},
},
];
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 扩展选择 selectType
上面介绍了,默认内置列表选择类型,本节主要介绍如何自定义业务选择。
- 复制
/src/components/ListSelect/src/selectType/userSelect.ts
文件 - 到当前目录下,重命名为
customSelect.ts
该文件名为 ListSelect 的selectType
参数值 - 修改
customSelect.ts
文件内容,自定义您的业务选择列表的searchForm
和tableColumns
- 修改
export default
中的itemCode
和itemName
为选择后返回的字段名 - 用法:
const schemas: FormSchema[] = [
{
label: '用户选择',
field: 'userCode',
fieldLabel: 'userName',
component: 'ListSelect',
componentProps: {
// 指定自定义的选择类型
selectType: 'customSelect',
},
},
];
2
3
4
5
6
7
8
9
10
11
12
# 属性
属性 | 类型 | 默认值 | 说明 |
---|---|---|---|
value | object | - | 控件值(双向绑定) |
labelValue | object | - | 控件值的标签,如 treeCode和treeName |
selectType | string | userSelect | 选择类型:userSelect:用户选择;empUserSelect:员工选择(含组织机构信息);可自定义 |
itemCode | string | - | 列表选择数据,回显和设置的字段编码属性名(优先级高于 userSelect.ts 里定义的 itemCode) |
itemName | string | - | 列表选择数据,回显和设置的字段显示名称属性名(优先级高于 userSelect.ts 里定义的 itemName) |
checkbox | boolean | false | 是否多选 |
allowInput | boolean | true | 是否允许输入 |
readonly | boolean | true | 是否只读 |
# RadioGroup 单选按钮组
在 Antdv 的 Radio 单选框 (opens new window) 基础之上封装,支持:字典数据。
v5.1.0 及之前版本:Antdv 2.x Radio 选择器 (opens new window)
# 使用
const schemas: FormSchema[] = [
{
label: '按钮组',
field: 'menuType',
component: 'RadioGroup',
componentProps: {
// 数据源1:固定数据
options: [
{ label: '选项1', value: '11' },
{ label: '选项2', value: '22' },
],
// 数据源2:字典数据
// dictType: 'sys_menu_type',
},
},
];
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 属性
属性 | 类型 | 默认值 | 说明 |
---|---|---|---|
value | object | - | 控件值(双向绑定) |
options | OptionsItem[] | [] | 下拉框选项,不启用 api 的时候,固定值可以使用 |
dictType | string | - | 字典类型的下拉框,设置字典类型 |
# RadioButtonGroup 按钮风格
在 Antdv 的 Radio 单选框 (opens new window) 基础之上封装,支持:字典数据。
v5.1.0 及之前版本:Antdv 2.x Radio 选择器 (opens new window)
# 使用
const schemas: FormSchema[] = [
{
label: '按钮组',
field: 'menuType',
component: 'RadioButtonGroup',
componentProps: {
// 数据源1:固定数据
options: [
{ label: '选项1', value: '11' },
{ label: '选项2', value: '22' },
],
// 数据源2:字典数据
// dictType: 'sys_menu_type',
},
},
];
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 属性
属性 | 类型 | 默认值 | 说明 |
---|---|---|---|
value | object | - | 控件值(双向绑定) |
options | OptionsItem[] | [] | 下拉框选项,不启用 api 的时候,固定值可以使用 |
dictType | string | - | 字典类型的下拉框,设置字典类型 |
# CheckboxGroup 复选框组
在 Antdv 的 Checkbox 多选框 (opens new window) 基础之上封装,支持:字典数据。
v5.1.0 及之前版本:Antdv 2.x Checkbox 多选框 (opens new window)
# 使用
const schemas: FormSchema[] = [
{
label: '按钮组',
field: 'menuType',
component: 'CheckboxGroup',
componentProps: {
// 数据源1:固定数据
options: [
{ label: '选项1', value: '11' },
{ label: '选项2', value: '22' },
],
// 数据源2:字典数据
// dictType: 'sys_menu_type',
},
},
];
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 属性
属性 | 类型 | 默认值 | 说明 |
---|---|---|---|
value | object | - | 控件值(双向绑定) |
options | OptionsItem[] | [] | 下拉框选项,不启用 api 的时候,固定值可以使用 |
dictType | string | - | 字典类型的下拉框,设置字典类型 |
# RangePicker 日期范围
使用 Antdv 的 DatePicker 日期选择框 (opens new window) 组件,常用于搜索栏的日期范围查询条件。
v5.1.0 及之前版本:Antdv 2.x DatePicker 日期选择框 (opens new window)
const searchForm: FormProps = {
baseColProps: { lg: 6, md: 8 },
labelWidth: 90,
schemas: [
{
label: t('创建时间'),
field: 'dateRange',
component: 'RangePicker',
componentProps: {},
},
],
// 定义自动转换规则[ [ 日期控件定义字段名, [ 开始日期查询参数, 结束日期查询参数 ] ] ]
fieldMapToTime: [['dateRange', ['beginDate', 'endDate']]],
};
2
3
4
5
6
7
8
9
10
11
12
13
14
# Upload 图片/文件上传
支持表单附件上传和编辑表格附件上传,可参考:testData/form.vue (opens new window)
# 使用
表单附件上传:
const inputFormSchemas: FormSchema[] = [
{
label: t('图片上传'),
field: 'dataMap',
component: 'Upload',
componentProps: {
loadTime: computed(() => record.value.__t),
bizKey: computed(() => record.value.id),
bizType: 'testData_image',
uploadType: 'image',
},
colProps: { lg: 24, md: 24 },
},
{
label: t('文件上传'),
field: 'dataMap',
component: 'Upload',
componentProps: {
loadTime: computed(() => record.value.__t),
bizKey: computed(() => record.value.id),
bizType: 'testData_file',
uploadType: 'all',
},
colProps: { lg: 24, md: 24 },
},
];
// 不可缺少,放在设置 record.value 代码后,用于更新上传列表
record.value = (res.testData || {}) as TestData;
record.value.__t = new Date().getTime();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
编辑表格附件上传:
<template>
<BasicTable>
<template #testDataChildUpload="{ record: childRecord }">
<BasicUpload
v-model:value="childRecord.dataMap"
:bizKey="childRecord.id"
:bizType="'testDataChild_file'"
:uploadType="'all'"
:loadTime="record.__t"
/>
</template>
</BasicTable>
</template>
<script lang="ts" setup>
const testDataChildColumns: BasicColumn[] = [
{
title: t('文件上传'),
dataIndex: 'upload',
width: 160,
align: 'left',
// 个性化列,可定义插槽(如样式,增加控件等)
slots: { customRender: 'testDataChildUpload' }, // 5.1.0 及之前
slot: 'testDataChildUpload', // 5.2.0+ (Antdv 3.x 不再使用 slots)
},
]);
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 属性
属性 | 类型 | 默认值 | 说明 |
---|---|---|---|
value | string[] | - | 已上传的文件列表,支持v-model |
showPreviewNumber | boolean | true | 是否显示预览数量 |
emptyHidePreview | boolean | false | 没有上传文件时是否隐藏预览 |
helpText | string | - | 帮助文本 |
maxSize | number | 2 | 单个文件最大体积,单位 M |
maxNumber | number | Infinity | 最大上传数量,Infinity 则不限制 |
accept | string[] | - | 限制上传格式,可使用文件后缀名(点号可选)或MIME字符串,优先级高于 uploadType 。例如 ['.doc,', 'docx','application/msword', 'image/*'] |
multiple | boolean | - | 开启多文件上传 |
uploadParams | any | - | 上传携带的参数 |
checkmd5 | boolean | true | 是否启用秒传(标准版/专业版) |
api | Fn | - | 上传接口,为上面配置的接口 |
bizKey | object | - | 当前表单主键值 |
bizType | string | - | 关联业务类型 |
uploadType | UploadType | all | 上传文件类型(可选值:image、media、file、all) |
loadTime | number | - | 加载时间戳,此为监听属性,方便刷新文件列表数据 |
UploadType
可选值 | 限定格式 |
---|---|
image | .gif,.bmp,.jpeg,.jpg,.ico,.png,.tif,.tiff,webp, |
media | .flv,.swf,.mkv,webm,.mid,.mov,.mp3,.mp4,.m4v,.mpc,.mpeg, .mpg,.swf,.wav,.wma,.wmv,.avi,.rm,.rmi,.rmvb,.aiff,.asf,.ogg,.ogv, |
file | .doc,.docx,.rtf,.xls,.xlsx,.csv,.ppt,.pptx,.pdf,.vsd,.txt, .md,.xml,.rar,.zip,.7z,.tar,.tgz,.jar,.gz,.gzip,.bz2,.cab,.iso,.ipa,.apk, |
all | 以上所有 |
注意:如需扩展,限定格式可在后端 application.yml 中设置。
# 事件
事件 | 回调参数 | 返回值 | 说明 |
---|---|---|---|
change | (fileList)=>void | 文件列表内容改变触发事件 | |
delete | (record)=>void | 在上传列表中删除文件的事件 |
# 图片最大宽高
当上传文件超过指定最大宽高的时候,后台自动转换为指定 imageMaxWidth、imageMaxHeight
const inputFormSchemas1: FormSchema[] = [
{
label: t('图片上传'),
field: 'dataMap',
component: 'Upload',
componentProps: {
// 省略其它属性。。。
imageMaxWidth: 1024,
imageMaxHeight: 768,
},
},
];
2
3
4
5
6
7
8
9
10
11
12
# 图片缩略图
指定缩略图名称 imageThumbName,后台可自动将图片生成对应的缩略图。
const inputFormSchemas1: FormSchema[] = [
{
label: t('图片上传'),
field: 'dataMap',
component: 'Upload',
componentProps: {
// 省略其它属性。。。
imageThumbName: '150x150.jpg',
},
},
];
2
3
4
5
6
7
8
9
10
11
# 必填验证
const inputFormSchemas1: FormSchema[] = [
{
label: t('图片上传'),
field: 'dataMap',
component: 'Upload',
componentProps: {
// 省略其它属性。。。
},
// 文件上传的必填验证实例
rules: [
{ required: true },
{
validator(_rule, value) {
return new Promise((resolve, reject) => {
const len = !value || value['testData_image__len'] || 0;
if (len == 0) reject(t('请上传图片'));
else resolve();
});
},
},
],
},
];
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Text 文本显示
支持 HTML、数据字典、文本内容的展示。
# 使用
const schemas: FormSchema[] = [
{
label: '文本内容',
field: 'testInput',
component: 'Text',
componentProps: {
dictType: 'sys_yes_no',
isHtml: false,
},
},
];
2
3
4
5
6
7
8
9
10
11
# 属性
属性 | 类型 | 默认值 | 说明 |
---|---|---|---|
value | object | - | 控件显示值 |
labelValue | object | - | 当value不存在的时候显示该值 |
dictType | string | - | 字典类型,根据字典类型显示字典标签名 |
isHtml | boolean | - | 是否 HTML 格式的文本 |
# Divider 分隔符
使用 Antdv 的 Divider 分割线 (opens new window) 组件。Divider
类型用于在 schemas
中占位,将会渲染成一个分割线(始终占一整行的版面),可以用于较长表单的版面分隔。请只将 Divider 类型的 schema 当作一个分割线,而不是一个常规的表单字段。
v5.1.0 及之前版本:Antdv 2.x Divider 分割线 (opens new window)
- 仅在
showAdvancedButton
为false
时才显示(也就是说如果启用了表单收起和展开功能时不会显示) - 使用
schema
中的label
以及helpMessage
来渲染分割线中的提示内容或标题 - 使用
componentProps
来设置除type
之外的属性,如:dashed是否虚线、orientation标题的位置
const inputFormSchemas: FormSchema[] = [
{
label: '',
field: 'detailInfo',
component: 'Divider',
colProps: { lg: 24, md: 24 },
},
];
2
3
4
5
6
7
8
# FormGroup 子表单
FormGroup
类型与Divider
类似,将会渲染成一个带表单子标题的分割线(占一整行的版面)不是一个常规的表单字段。
const inputFormSchemas: FormSchema[] = [
{
label: t('详细信息'),
field: 'detailInfo',
component: 'FormGroup',
colProps: { lg: 24, md: 24 },
},
];
2
3
4
5
6
7
8
# 自定义组件方法
ComponentType 内置组件,无法满足所有需求,这是您可以自定义渲染组件内容
# slot 插槽方式
自定义渲染内容
提示
使用插槽自定义表单域时,请注意 Antdv 有关 FormItem 的 相关说明 (opens new window)。
v5.1.0 及之前版本:Antdv 2.x Form 表单 (opens new window)
<template>
<div class="m-4">
<BasicForm @register="register">
<template #customSlot="{ model, field }">
<a-input v-model:value="model[field]" />
</template>
</BasicForm>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { BasicForm, FormSchema, useForm } from '/@/components/Form';
export default defineComponent({
name: 'FormDemo',
components: { BasicForm },
setup() {
const schemas: FormSchema[] = [
{
field: 'field1',
component: 'Input',
defaultValue: '123',
label: '字段1',
slot: 'customSlot',
},
];
const [register] = useForm({
labelWidth: 100,
actionColOptions: {
span: 24,
},
schemas,
});
return {
register,
};
},
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# render 函数式
自定义渲染内容
<template>
<div class="m-4">
<BasicForm @register="register" @submit="handleSubmit" />
</div>
</template>
<script lang="ts">
import { defineComponent, h } from 'vue';
import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
import { useMessage } from '/@/hooks/web/useMessage';
import { Input } from 'ant-design-vue';
const schemas: FormSchema[] = [
{
field: 'field1',
component: 'Input',
label: '字段1',
colProps: {
span: 8,
},
rules: [{ required: true }],
// 通过函数渲染一个 Input
render: ({ model, field }) => {
return h(Input, {
placeholder: '请输入',
value: model[field],
onChange: (e: ChangeEvent) => {
model[field] = e.target.value;
},
});
},
},
{
field: 'field2',
component: 'Input',
label: '字段2',
colProps: {
span: 8,
},
rules: [{ required: true }],
// 指定 Input 的 slot
renderComponentContent: () => {
return {
suffix: () => 'suffix',
};
},
},
];
export default defineComponent({
components: { BasicForm },
setup() {
const { createMessage } = useMessage();
const [register, { setProps }] = useForm({
labelWidth: 100,
schemas,
showActionButtonGroup: true,
submitButtonOptions: {
text: '提交',
},
actionColOptions: {
span: 8,
},
});
return {
register,
schemas,
handleSubmit: (values: any) => {
createMessage.success('表单值: ' + JSON.stringify(values));
},
setProps,
};
},
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# 新建组件方式
方式 1
在 src/components/Form/src/componentMap.ts (opens new window) 内,添加需要的组件,并在上方 ComponentType 添加相应的类型 key
这种写法适用与适用频率较高的组件
componentMap.set('componentName', 组件);
// ComponentType
export type ComponentType = xxxx | 'componentName';
2
3
方式 2
使用 useComponentRegister 进行注册
这种写法只能在当前页使用,页面销毁之后会从 componentMap 删除相应的组件
import { useComponentRegister } from '/@/components/Form';
import { StrengthMeter } from '@/components/StrengthMeter';
useComponentRegister('StrengthMeter', StrengthMeter);
2
3
提示
方式 2 出现的原因是为了减少打包体积,如果某个组件体积很大,用方式 1 的话可能会使首屏体积增加
# 应用示例集合
# 显示禁用
自定义表单控件的:显示/禁用(ifShow/show/dynamicDisabled)
区别:ifShow 是否渲染组件;show 正常渲染组件,确定是否显示(display: none)
<template>
<div class="m-4">
<BasicForm @register="register" />
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
const schemas: FormSchema[] = [
{
field: 'field1',
component: 'Input',
label: '字段1',
colProps: {
span: 8,
},
show: ({ values }) => {
return !!values.field5;
},
},
{
field: 'field2',
component: 'Input',
label: '字段2',
colProps: {
span: 8,
},
ifShow: ({ values }) => {
return !!values.field6;
},
},
{
field: 'field3',
component: 'DatePicker',
label: '字段3',
colProps: {
span: 8,
},
dynamicDisabled: ({ values }) => {
return !!values.field7;
},
},
];
export default defineComponent({
components: { BasicForm },
setup() {
const [register, { setProps }] = useForm({
labelWidth: 120,
schemas,
actionColOptions: {
span: 24,
},
});
return {
register,
schemas,
setProps,
};
},
});
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# 表单验证
{
label: t('员工工号'),
field: 'employee.empNo',
component: 'Input',
componentProps: {
maxlength: 32,
},
required: false, // 如果只是必填,可以这样简写,否则使用 rules
rules: [
// 是否必填
{ required: false },
// 长度校验
{ min: 4, max: 20, message: t('请输入长度在 4 到 20 个字符之间') },
// 邮箱校验
{ type: 'email', message: t('请填写正确的邮箱地址') }
// 正则表达式校验
{ pattern: /^[\u0391-\uFFE5\w]+$/, message: t('不能输入特殊字符') },
// 自定义验证,举例:远程验证工号是否存在
{
validator(_rule, value) {
return new Promise((resolve, reject) => {
if (!value || value === '') return resolve();
checkEmpNo(record.value.employee?.empNo || '', value)
.then((res) => (res ? resolve() : reject(t('员工工号已存在'))))
.catch((err) => reject(err.message || t('验证失败')));
});
},
},
// 高级示例:跨字段校验,如:密码与确认密码是否相同
{
field: 'newPassword',
label: '新密码',
component: 'StrengthMeter',
componentProps: {
placeholder: '新密码',
},
rules: [
{
required: true,
message: '请输入新密码',
},
],
},
{
field: 'confirmNewPassword',
label: '确认密码',
component: 'InputPassword',
dynamicRules: ({ values }) => {
return [
{
required: true,
validator: (_, value) => {
if (!value) {
return Promise.reject('密码不能为空');
}
if (value !== values.newPassword) {
return Promise.reject('两次输入的密码不一致!');
}
return Promise.resolve();
},
},
];
},
},
],
ifShow: () => op.value === 'add' || op.value === 'edit',
},
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
trigger | 校验触发的时机 | 'blur' | 'change' |
enum | 枚举类型 | string | - |
len | 字段长度 | number | - |
max | 最大长度 | number | - |
message | 校验文案 | string | - |
min | 最小长度 | number | - |
pattern | 正则表达式校验 | RegExp | - |
required | 是否必选 | boolean | false |
transform | 校验前转换字段值 | function(value) => transformedValue:any | - |
type | 内建校验类型,可选项 | string | 'string' |
validator | 自定义校验(注意,callback 必须被调用) | function(rule, value, callback) | - |
whitespace | 必选时,空格是否会被视为错误 | boolean | false |
更多:Antdv Form 校验规则 (opens new window) v5.1.0 及之前版本:Antdv 2.x Form 校验规则 (opens new window)
更多高级用法可研究 async-validator (opens new window)。
# 子表表单验证
testDataChildTable.setColumns([
{
title: t('单行文本'),
dataIndex: 'testInput',
width: 130,
align: 'left',
editRow: true,
editComponent: 'Input',
// 编辑子表的必填验证
editRule: true,
},
{
title: t('多行文本'),
dataIndex: 'testTextarea',
width: 130,
align: 'left',
editRow: true,
editComponent: 'InputTextArea',
// 子表自定义验证实例
editRule: (value, _record) => {
return new Promise((resolve, reject) => {
if (!value || value === '') return resolve();
if (value.length < 3) return reject('至少3个字符');
return resolve(); // 验证成功
});
},
},
]);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 组件联动例子
表单值改变的时候操作表格或者修改表单内其他元素的值,实现组件联动:
{
component: 'Input',
componentProps: ({ schema, tableAction, formActionType, formModel }) => {
return {
// xxxx props
onChange: (e: ChangeEvent) => {
const { reload } = tableAction
reload()
// or
formModel.xxx = '123'
}
};
},
}
2
3
4
5
6
7
8
9
10
11
12
13
14
根据表单组件值进行显示隐藏其它组件;支持插槽中多个组件;支持表单带验证
<template>
<BasicForm @register="registerForm1">
<template #testCheckbox="{ model, field }">
<Form.Item class="inline-block" :name="field">
<CheckboxGroup
:value="model[field]"
@change="
model[field] = $event || ''; // 给表单赋值(写到这里是为了方便演示,可写到一个函数里)
$event && (model[field + 'Other'] = ''); // 不选“无”的时候,清空后面的复选框和输入框
"
:options="[{ label: '无', value: '0' }]"
/>
<div class="ml-3 inline-block"></div>
<CheckboxGroup
:value="model[field]"
@change="model[field] = $event || ''"
:dictType="'sys_menu_type'"
:disabled="model[field] == '0' /* 选择“无”的时候禁用 */"
/>
</Form.Item>
<div class="ml-2 inline-block"></div>
<Form.Item
class="inline-block"
:name="field + 'Other'"
:rules="[
// 如果选择了最后一个复选框,则出现输入框,并启用表单验证
{ required: (',' + model[field] + ',').indexOf(',2,') != -1, message: '请填写' },
]"
v-show="(',' + model[field] + ',').indexOf(',2,') != -1 /* 是否显示输入框 */"
>
<Input
:value="model[field + 'Other']"
@change="model[field + 'Other'] = $event.target.value"
style="width: 200px"
/>
</Form.Item>
</template>
</BasicForm>
</template>
<script lang="ts" setup>
import { CheckboxGroup } from '/@/components/Form';
import { Input, Form } from 'ant-design-vue';
const record = ref<TestData>({} as TestData);
const inputFormSchemas1: FormSchema[] = [
{
label: t('复选框'),
field: 'testCheckbox',
component: 'Input',
slot: 'testCheckbox',
},
];
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52