之前开发的时间比较赶,所以在某些还没弄明白的地方我直接使用了 v-model
来绑定数据,没并没有使用 v-decorator
,所以表单验证需要自己手动去写,异常提示也是需要单独的去做,
现在空下来了,重新整理了一下业务代码,总的来说大部分的表单元素都有demo可以对照着看,复杂的部分也只是上传组件或者一些联动的部分。
表单验证
使用 this.$form.createForm()
创建的收集器,可以通过 validateFields
和 validateFieldsAndScroll
这两个api对收集器进行数据校验,当然需要提前在 form-item
中配置校验规则。
配置校验规则
<a-form-item>
<a-input
v-decorator="['email',{
rules: [
{ required: true, message: '请输入您的电子邮箱!' },
{ type: 'email', message: '请输入正确的电子邮箱号!' },
],
}]"
placeholder="您的电子邮箱
>
<a-icon slot="prefix" type="mail" />
</a-input>
</a-form-item>
表单校验
methods:{
// 保存
handleSubmit() {
// 触发表单验证
this.form.validateFields(['email', 'password'],(err, values) => {
// ['email', 'password'] 是需要校验的字段名
...
})
},
// 保存
handleSubmit() {
// 触发表单验证
this.form.validateFields(,(err, values) => {
// 也可以直接省略 [fieldNames] 校验全部数据
...
})
},
}
这样每次在提交表单时就会触发数据校验,并且在 err
中会返回错误信息,values
中返回校验过的数据,搭配 if(!err)
就可以完成业务操作了。
头像上传组件
使用 Upload
组件的 picture-card
模式来作为头像上传组件,在@change事件中对 form
进行 setFieldsValue
来赋值给 a-input:hidden
这样就可以进行校验和返回值了。
<template>
<a-form :form="form" @submit.prevent="handleSubmit">
<a-form-item>
<a-upload
listType="picture-card"
class="avatar-uploader"
:headers="headers"
:showUploadList="false"
:action="uploadURL"
:beforeUpload="beforeUpload"
@change="handleChange"
>
<img v-if="avatar" :src="avatar" alt="avatar" style="width:100%;" />
<div v-else>
<a-icon :type="loading ? 'loading' : 'plus'" />
<div class="ant-upload-text">Upload</div>
</div>
</a-upload>
<a-input type="hidden" v-decorator="['avatar', validatorRules.avatar]" />
</a-form-item>
<a-form-item>
<a-button type="primary" html-type="submit" block>保存</a-button>
</a-form-item>
</a-form>
</template>
<script>
export default {
name: 'UserInfoEdit',
data() {
return {
avatar: '',
loading: false,
validatorRules: {
avatar: {
rules: [{ required: true, message: '请上传头像!' }]
},
},
form: this.$form.createForm(this),
}
},
methods:{
// 头像上传前检查
beforeUpload(file) {
const isLt2M = file.size / 1024 / 1024 < 2
if (!isLt2M) {
this.$message.error('图片最大限制为2MB!')
}
return isLt2M
},
// 头像修改
handleChange(info) {
if (info.file.status === 'uploading') {
this.loading = true
return
}
if (info.file.status === 'done') {
this.form.setFieldsValue({ avatar: info.file.response.url }) // 短链接提交给后端的数据
this.avatar = info.file.response.thumbUrl // 赋值给展示链接展示链接
this.loading = false
}
},
// 保存
handleSubmit() {
// 触发表单验证
this.form.validateFields((err, values) => {
if (!err) {
// 具体业务代码
}
})
},
}
}
</script>
当然也可以直接绑定在 Upload
组件上,我只是偷个懒不想再在验证之后去修改数据了。
动态校验规则
比如说,可以修改上传数量限制。这个时候直接修改规则并不会直接重新验证,需要重新修改数据之后才会再次校验。
- 如果动态校验,需要校验的时候在 option 中加上
{ force: true }
// 伪代码片段
methods:{
// 保存
handleSubmit() {
// 触发表单验证
this.form.validateFields({ force: true },(err, values) => {
...
})
},
}
一个FormItem中多个被装饰过的表单元素
有时候会遇到这样的的情况,在一个FormItem中有多个Input或者Select联动。
如果只是使用 v-decorator
来装饰会有警告提示:
Warning: [antdv: Form.Item] Cannot generate `validateStatus` and `help` automatically, while there are more than one `getFieldDecorator` in it.`
反正就是 一个 Form.Item 建议只放一个被 getFieldDecorator 或 v-decorator 装饰过的 child
如果存在多个就需要自己配置 help
, required
, validateStatus
,这点可以在 API文档 中看到。
如何配置呢?附一个伪代码例子
<template>
<a-form :form="form">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="地址"
:help="help"
:validateStatus="validateStatus"
>
<a-input-group compact>
<a-select
style="width:33%"
placeholder=" - "
v-decorator="['provinceId', validatorRules.provinceId]"
@change="handleCityChange"
>
<a-spin v-if="regionList.province.fetch" slot="notFoundContent" size="small" />
<a-select-option
v-for="i in regionList.province.list"
:key="i.id"
:title="i.regionName"
>{{ i.regionName }}</a-select-option>
</a-select>
<a-select
style="width:33%"
placeholder=" - "
v-decorator="['cityId',validatorRules.cityId]"
@change="handleCityChange"
>
<a-spin v-if="regionList.city.fetch" slot="notFoundContent" size="small" />
<a-select-option
v-for="i in regionList.city.list"
:key="i.id"
:title="i.regionName"
>{{ i.regionName }}</a-select-option>
</a-select>
<a-select
style="width:33%"
placeholder=" - "
v-decorator="['areaId', validatorRules.areaId]"
>
<a-spin v-if="regionList.area.fetch" slot="notFoundContent" size="small" />
<a-select-option
v-for="i in regionList.area.list"
:key="i.id"
:title="i.regionName"
>{{ i.regionName }}</a-select-option>
</a-select>
</a-input-group>
</a-form-item>
<a-form-item :wrapperCol="offsetWrapperCol">
<a-button type='primary' @click="handleSubmit">提交</a-button>
</a-form-item>
</a-form>
</template>
<script>
export default {
name: 'address-modal',
data() {
return {
// 自定义校验信息
validateStatus: '',
help: '',
form: this.$form.createForm(this),
confirmLoading:false,
// 校验规则
validatorRules: {
provinceId: { rules: [{ required: true, message: '请选择省份' }] },
cityId: { rules: [{ required: true, message: '请选择城市' }] },
areaId: { rules: [{ required: true, message: '请选择地区' }] },
},
// 城市列表数据
regionList: {
province: {
list: [],
fetch: false
},
city: {
list: [],
fetch: false
},
area: {
list: [],
fetch: false
}
},
// 表单栅格
labelCol: {
xs: { span: 24 },
sm: { span: 5 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 }
},
offsetWrapperCol: {
xs: { span: 24 },
sm: { span: 16, offset: 5 }
},
}
},
methods: {
handleSubmit() {
// 监听表单提交事件,触发表单验证
this.form.validateFields((err, values) => {
if (!err) {
// 这里是验证通过之后的操作
} else {
// 校验失败,自定义校验信息
// 这边三个值依次取值,返回第一个有错误信息的属性
const onErr = err.provinceId || err.cityId || err.areaId
if (onErr && onErr.errors) {
// 如果有错误信息,设置错误状态
this.validateStatus = 'error'
// 一个错误信息内部是校验内容是以数组的形式返回的,可以在data.validatorRules中的rules中看到顺序
this.help = onErr.errors[0].message
} else {
// 如果没有报错的情况
this.validateStatus = 'success'
this.help = ''
}
}
})
},
handleCityChange(value, option) {
// 这里是监听改变的业务逻辑,比如获取下级地址列表
},
}
}
</script>
两种提交方式(存为草稿和保存发布)
保存数据分委两种,一种是存为草稿,另一种是保存并发布;
- 存为草稿则只需要验证一部分必填字段,其它字段如果填写就校验,并且收集所有已经填写的字段。
- 保存校验所有字段,并且需要匹配所有规则。
暂时还没有想好,现阶段分开两个函数,存为草稿是在 validateFields
中的规则内填写需要校验的字段,并且在if(!err)
中,使用 getFieldsValue
获取整个表单数据
遇到问题
#1. 在表单中使用 <a-switch />
组件时控制台出现警告
Warning: [antd: Checkbox] `value` is not validate prop, do you mean `checked`?
其原因是,没有设置 valuePropName
属性,直接使用 v-decorator
进行绑定时,就会出现这个问题。
为其设置 valuePropName
属性为 checked
即可。
<template>
<a-form :form="form">
<a-form-item label="Switch">
<a-switch
v-decorator="[
'switch',
{
rules: [],
valuePropName: 'checked', // 增加此项
initialValue: false
}
]"
/>
</a-form-item>
</a-form>
</template>
具体可以查看 AntD Vue
的文档 此处
附:
AntD Vue
1.5.0+ 增加了新组件FormModel 表单 可以通过v-model
绑定收集数据,并且校验数据了