本人封装了一个基于 ant 的 form 表单,以下是使用方法
表单属性
| 属性名 | 解释 |
|---|---|
| fields | 规定你需要生成表单的值结构 |
| formLayout | 表单布局 |
| defaultSpan | 你的表单默认占用宽度 |
| ref | 获取表单的 ref,用于提交按钮 |
| initialValues | 初始值,用于表单回显以及表单重置 |
| formRules | 自定义校验表单 |
fields 属性配置
fields是一个数组对象结构
通用
| 属性名 | 解释 | 类型 |
|---|---|---|
| name | 绑定的数据名 | string |
| label | 左侧名称 | string |
| type | 数据类型 | string |
| required | 星星,只起到展示左右(主要是为插槽校验考虑) | boolean |
| errorMessage | 必填错误信息 | string |
| requiredFlag | 确定是否为必填项 | boolean |
| componentProps | ant 组件本身自带的属性 | Object |
| span | 表单占用宽度,取值这个即不会取值默认 | number |
| slot | 插槽 | boolean |
| dependency | 根据前面的表单选中的内容而决定是否展示 | { dependsOn: “根据那个表单的类型,绑定他的值”, value: “当前面绑定的值为某个时,显示这个表单的值”,} |
| slotFlag | 不使用表单 a-form-item 的插槽 | true 则不使用 |
type 类型
| Type 类型 默认是 input | 原生 | 解释 | 数据格式 |
|---|---|---|---|
| input | a-input | 输入框 | |
| input-number | a-input-number | 数字输入框 | |
| select | a-select | 下拉框 | |
| radio | a-radio | 单选 | |
| checkbox | a-checkbox | 多选 | |
| cascader | a-cascader | 级联 | [{}] |
| date | a-date | 日期 | |
| switch | a-switch | 开关 | |
| time | a-time | 时间 | HH:mm:ss |
| textarea | a-textarea | 文本域 | |
| imgUpload | a-upload | 原本的上传包括了图片上传以及文件上传,html 结构和样式无法统一,因此建议使用插槽去做,不要使用组件 | |
| treeSelect | a-tree-select | tree 的下拉 |
以下是需要注意的点
time 类型注意点
time类型需要下载 ant datajs,并且需要导入且按照他的定义格式,我个人觉得太麻烦了,通过绑定value-format="HH:mm:ss"这个值去定义会好很多,例如
{
name: "time",
label: "时间",
type: "time",
componentProps: { "value-format": "HH:mm:ss" },
},
cascader 注意点
在使用级联选择器时,当父亲的宽度低于子孙原生宽度时,报错ResizeObserver loop limit exceeded ,由于他是由递归写成的,结构的改变会导致他的不断的回流,直到报错。
解决办法:
在给他赋值初始值为 cascader: [{}],亦或者忽略
select 注意点
在我们使用 select 组件时,一般需要会需要自定义 label,value,options 字段,这这里面如何处理?直接使用 ant 的属性即可
componentProps: {
"field-names": { label: "name", value: "id", options: "children" }
}
cascader,treeSelect组件同理(使用名 fieldNames)
checkbox 与 radio
checkbox 有时会包住a-checkbox使用,由于代码底层使用的动态组件,我并未对其封装,如果需要用,请使用插槽,平常用法:
componentProps: {
options: [数据]
}
radio 同理
required&errorMessage&requiredFlag 解释
这两个属性是相辅相成的,需要同时进行,required 并非真正的进行校验。而是只是有个必选的星号在那里,处理逻辑并未沿用 ant 组件内部校验,而是通过自己的业务逻辑去判断并产生消息提示
requiredFlag需定义才能开启校验,required 只是星号,主要是为了插槽的表单做校验
errorMessage不是必须的,底层做了保底,如果不传,则会采用默认信息提示
插槽表单如何校验?
1.插槽表单无需定义 required&errorMessage,只需要 required,让他把星号展示出来。
2.在提交按钮校验后去判断他这个值并进行校验
示例:
baseForm.value.handleSubmit((formData: Record<string, any>) => {
if (!baseForm.value.formData.memberProjectCategoryId) {
message.error("项目分类不能为空");
return;
}
// 调用接口
});
});
componentProps
componentProps可以说是最重要的,打个比方,我写一个文本域,即备注表单,我们需要如何定义fields配置。
const fields = ref([
name:'remark', // 绑定值
label:'备注', // 左侧标题
type:'textarea', // 表单类型
required:true, // 是否校验
errorMessage:'请填写备注' // 校验信息
])
这样,一条表单就配置好了。但是此时你想要把文本域展示默认值,同时控制在 2-4 行,同时限制他的字数,并显示剩余字数,如何处理?使用componentProps这个属性,继上面的代码继续
const fields = ref([
name:'remark', // 绑定值
label:'备注', // 左侧标题
type:'textarea', // 表单类型
required:true, // 是否校验
errorMessage:'请填写备注', // 校验信息
componentProps:{
"auto-size": { minRows: 2, maxRows: 4 }, // 控制在2-4行
maxlength: 10, // 最大字数
placeholder: "文本", // 默认文本
"show-count": true // 展示剩余数字
}
])
注意:对象的键,原本就是字符串,因此我们对于带 - 的属性把他写成字符串即可
这样就 ok 了,componentProps中的属性均来自 ant 组件,想要加什么效果加好了即可。
span 属性
共 24 份,设置了span这个值,将替代默认defaultSpan
slot 属性
slot即插槽,他的值为布尔值,true 为开启插槽,反正不开启,如何使用?
比如你想要在某条表单后面写入插槽,只需要在fields将他定义在那条数据的后面即可,例如:
第一步 定义
const fields: Field[] = [
{
name: 'username',
label: 'Username',
type: 'input',
errorMessage: '请输入姓名',
required: true,
span: 12,
},
{
name: 'sex',
label: '性别',
type: 'input',
errorMessage: '请输入性别',
required: true,
slot: true,
span: '12',
},
]
以上示例即把性别插入姓名后方,如果需要插入到他的前面,即需要把数据放在他的前面即可
第二步 使用
<CustomForm
ref="customForm"
:fields="fields"
formLayout="vertical"
:initialValues="initialValues"
:defaultSpan="8"
>
<template #sex="{ field, formData }">
<div>
<a-input v-model:value="formData.sex" placeholder="你好"></a-input>
</div>
</template>
</CustomForm>
看示例,作用域插槽绑定的插槽名,就是你定义的那条数据的name属性值,#sex, 同时你可以在你插入的内容中绑定数据,作用域插槽把数据都给你传递回来了,如何绑定?formData是用于回显的数据对象,给他绑定上对应,即:formData就是initialValues
formLayout
formLayout 就是 form 表单如何布局,ant 给了三种属性值 分别是
| horizontal | 默认值 |
|---|---|
| vertical | |
| inline |
defaultSpan
defaultSpan 就是你表单默认占多少位置,如果数据设置了 span,则会被替换掉,默认值是 24 份
initialValues
initialValues 是数据初始值,可以用于数据初始化及数据回显
ref
用于获取表单的实例对象,用于表单的提交,可以通过他拿到所填数据,以及数据校验
const customForm = ref()
const onSubmit = () => {
customForm.value.handleSubmit((formData: Record<string, any>) => {
console.log('Form Submitted:', formData)
})
}
formData就是你提交表单所需数据
dependency
用于根据前面表单的数据动态展示后面的表单dependsOn: 绑定哪个表单? 他的值写绑定表单的绑定值value:绑定表单选中某个值显示
dependency: {
dependsOn: "radioValue",
value: "female",
}
// 选中radioValue值,当他的值为female,则显示
slotFlag
这个主要是作用域表单的隐藏与显示,可以作为动态表单,slot 插槽隐藏时,会有一块占地区域,如果不想要,则使用 slotFlag,且自己在外部套用一层 a-form-item
// 使用slot的插槽 隐藏占用位置
<template #associationProjectCode="{ field, formData }">
<a-select
v-model:value="formData.associationProjectCode"
optionLabelProp="label"
show-search
placeholder="请选择诊疗项目"
:default-active-first-option="false"
:show-arrow="false"
:filter-option="false"
:not-found-content="null"
:options="option"
@search="handleSearch"
@change="handleChange"
></a-select>
</template>
// 使用slotFlag的插槽 隐藏不占位置 建议在使用表单的事件时使用
<template v-if="treeId == 0" #memberProjectCategoryId="{ field, formData }">
<a-form-item
:label="field.label"
:required="field.required"
:name="field.formName"
>
<a-select
v-model:value="formData.memberProjectCategoryId"
optionLabelProp="label"
show-search
placeholder="请选择诊疗项目"
:default-active-first-option="false"
:show-arrow="false"
:filter-option="false"
:not-found-content="null"
:options="options"
@search="handleSearch"
@change="handleChange"
></a-select>
</a-form-item>
</template>
动态表单建议使用 dependency,而不是使用 slotFlag,如果需要触发表单的某个事件时,使用 slotFlag.
formRules
用于自定义表单,需要配合 formName 使用
{
name: "username",
label: "姓名",
type: "input",
span: 12,
formName: "username",
},
const formRules = {
username: [
{
required: true,
message: 'Please input Activity name',
trigger: 'change',
},
{ min: 3, max: 5, message: 'Length should be 3 to 5', trigger: 'blur' },
],
}
5.下载使用
1.下载
npm i ant-base-form //下载
2.在 main.ts 引入
import BaseForm from 'ant-base-form'
import 'ant-base-form/dist/style.css'
const app = createApp(App)
app.use(BaseForm)
注意,如若样式结构出现问题,则需要将 ant 组件库及样式先引入,再引入这个,同时使用是也放在 ant 后,如若未出现,则正常使用
3.在需要使用的组件中使用
<template>
<BaseForm
ref="baseForm"
:fields="fields"
formLayout="vertical"
:initialValues="initialValues"
:defaultSpan="8"
>
// 插槽
<template #sex="{ field, formData }">
<div>
<a-input v-model:value="formData.sex" placeholder="你好"></a-input>
</div>
</template>
</BaseForm>
</template>
<script lang="ts" setup>
// 初始值
const initialValues = {
username: '',
sex: '',
aaaa: '',
}
// 生成表单类型
const fields = [
{
name: 'username',
label: 'Username',
type: 'input',
errorMessage: '请输入姓名',
required: true,
span: 12,
},
{
name: 'sex',
label: '性别',
type: 'input',
errorMessage: '请输入性别',
required: true,
slot: true,
span: '24',
},
{
name: 'aaaa',
label: 'aaaaa',
type: 'textarea',
componentProps: {
'auto-size': { minRows: 5, maxRows: 5 },
maxlength: 10,
placeholder: '文本',
'show-count': true,
},
},
]
// 点击提交 拿到表单数据
const baseForm = ref()
// 绑定表单的按钮,用于数据校验以及拿到数据
const onSubmit = () => {
baseForm.value.handleSubmit((formData: Record<string, any>) => {
console.log('Form Submitted:', formData)
})
}
</script>
6.示例
// 初始值
const initialValues = {
username: '',
area: '',
date: undefined,
flag: true,
checkbox: [],
radio: '',
remark: '',
}
// 生成表单类型
const fields: any = [
{
name: 'username',
label: '姓名',
type: 'input',
span: 12,
formName: 'username',
},
{
name: 'area',
label: '地区',
type: 'select',
span: '12',
formName: 'area',
componentProps: {
options: [
{ label: '苹果', value: 'Apple' },
{ label: '梨', value: 'Pear' },
{ label: '橘子', value: 'Orange' },
],
},
},
{
name: 'date',
label: '时间',
type: 'date',
span: '12',
formName: 'date',
componentProps: {
format: 'YYYY/MM/DD',
},
forName: 'date',
},
{
name: 'flag',
label: '开关',
type: 'switch',
span: '12',
},
{
name: 'checkbox',
label: '多选',
type: 'checkbox',
span: '12',
componentProps: {
options: [
{ label: '苹果', value: 'Apple' },
{ label: '梨', value: 'Pear' },
{ label: '橘子', value: 'Orange' },
],
},
},
{
name: 'radio',
label: '单选',
type: 'radio',
span: '12',
componentProps: {
options: [
{ label: '苹果', value: 'Apple' },
{ label: '梨', value: 'Pear' },
{ label: '橘子', value: 'Orange' },
],
},
},
{
name: 'remark',
label: '备注',
type: 'textarea',
span: '12',
},
]
const formRules = {
username: [
{
required: true,
message: 'Please input Activity name',
trigger: 'change',
},
{ min: 3, max: 5, message: 'Length should be 3 to 5', trigger: 'blur' },
],
area: [
{
required: true,
message: 'Please select Activity zone',
trigger: 'change',
},
],
date: [
{
required: true,
message: 'Please pick a date',
trigger: 'change',
type: 'object',
},
],
}
// 点击提交 拿到表单数据
const baseForm = ref()
// 表单自定义校验
const onSubmit1 = () => {
baseForm.value.customRuleSubmit((formData: Record<string, any>) => {
console.log('Form Submitted:', formData)
})
}
7.数据重置
baseForm.value.resetForm()
8.数据回显
baseForm.value.dataPlayBack(回显数据对象)
9.数据回显定义某一个数据或更改某一个数据
baseForm.value.formData.属性值 = 数据