antdv vue。表单 自定义组件使用 v-decorator
antd vue 中,在 form 表单中的自定义组件使用 v-decorator
问题描述
项目需要,在表单中上传图片,所以要自己定以一个上传图片的组件,直接在 form 中使用,但是普通的自定义组件无法使用表单的 v-decorator。
分析
this.form.getFieldDecorator(id, options) 和 v-decorator="[id, options]"
经过 getFieldDecorator 或 v-decorator 包装的控件,表单控件会自动添加 value(或 valuePropName 指定的其他属性) onChange(或 trigger 指定的其他属性),数据同步将被 Form 接管,这会导致以下结果:
你不再需要也不应该用 onChange 来做同步,但还是可以继续监听 onChange 等事件。
你不能用控件的 value defaultValue 等属性来设置表单域的值,默认值可以用 getFieldDecorator 或 v-decorator 里的 initialValue。
你不应该用 v-model,可以使用 this.form.setFieldsValue 来动态改变表单值。
大概描述一下就是,一旦在 form 下使用了 v-decorator 之后,就不需要使用 v-model,其实实现上也有所相同,在自定义组件中需要自己定以 model 的东西,详细可以查阅官网。
简单说明
通俗来说,想使用 v-decorator,就必须要有个 value 想子组件传递数据。和一个 change 方法将子组件的数据变动告诉父组件,下面看部分代码
model: { prop: 'value', event: 'change' }, props: { value: { type: String // 这个参数是v-decorator给子组件传值用的 // 这里不要给默认值, 在form下使用会爆警告 Warning: SquareUpload `default value` can not collect, please use `option.initialValue` to set default value. } } watch: { // 监听数据变化,及时提交给父组件 fileList: { deep: true, immediate: true, handler: function (newV, oldV) { // 向父组件更新 this.$emit('change', temp) } } }
注意:value 不要给默认值,不然会爆警告default value can not collect, please use option.initialValue to set default value.
例子,封装一个上传图片的组件,在 form 中使用
子组件
<template>
<div>
<!-- one -->
<div class="clearfix">
<a-upload
name="upfile"
:action="apiUrl"
listType="picture-card"
:fileList="imageList"
:before-upload="beforeUpload"
@preview="handlePreview"
@change="imgChange"
>
<div v-if="imageList.length < maxListSize ">
<a-icon type="plus"/>
<div class="ant-upload-text">上传图片</div>
</div>
</a-upload>
<a-modal :visible="previewVisible" :footer="null" @cancel="previewCancel">
<img alt="example" style="width: 100%" :src="previewImage"/>
</a-modal>
</div>
</div>
</template>
<script>
import {randomUUID, isJson} from "@util/functionBox";
export default {
name: "imgUpload",
props: {
value: {
type: String
// 这个参数是v-decorator给子组件传值用的
// 这里不要给默认值, 在form下使用会爆警告 Warning: SquareUpload `default value` can not collect, please use `option.initialValue` to set default value.
},
format: {type: Boolean, default: false},
maxListSize: {type: Number, default: 1},
},
model: {
prop: 'value',
event: 'change'
},
data() {
return {
apiUrl: this.apiBaseURL + "/base/upload/upload_image",
imageList: [],
previewVisible: false,
previewImage: "",
}
},
watch: {
// 监听父组件传递过来的图片列表信息
value: {
deep: true,
immediate: true,
handler: function (newV,oldV) {
// 向父组件更新
if (newV === null || newV === '' || newV === undefined) {
this.imageList = []
return
}
// 需要清空原有的文件列表,否则会出现多个🙅
this.imageList = []
if (Array.isArray(newV)) {
//以防万一,避免出错
} else {
if (this.format && isJson(newV)) {
//需要格式化且是JSON格式才执行,否则会死循环输出
let caList = JSON.parse(newV)
if (caList && caList.length && caList.length != 0) {
// var newImgList = [];
for (let i = 0; i < caList.length; i++) {
this.pushImg(caList[i])
}
// this.imageList = newImgList
}
} else {
this.pushImg(newV)
}
}
// this.$emit('change', newV)
}
},
//监听数据变化,及时提交给父组件
imageList: {
deep: true,
immediate: true,
handler: function (fileList, oldV) {
// 向父组件更新
if (this.imageList.length === 0) {
return
}
// this.imageList = fileList;
let urlInfo = null;
if (
fileList.length != 0 &&
fileList[fileList.length - 1].status === "done") {
// 处理数据
if (!this.format) {
urlInfo = fileList[0].response.data
} else {
let imgs = [];
for (let i = 0; i < fileList.length; i++) {
if (fileList[i].response) {
imgs.push(fileList[i].response.data);
}
// if (fileList[i].url) {
// imgs.push(fileList[i].url);
// }
}
urlInfo = JSON.stringify(imgs);
}
this.$emit('change', urlInfo)
}
}
}
},
methods: {
imgChange({fileList}) {
this.imageList = fileList;
if (
fileList.length != 0 &&
fileList[fileList.length - 1].status === "done") {
this.$message.success("上传成功!");
// this.$emit('change', this.imageList)
}
},
/**取消阅览 **/
previewCancel() {
this.previewVisible = false;
},
handlePreview(file) {
this.previewImage = file.url || file.thumbUrl;
this.previewVisible = true;
},
beforeUpload(file) {
// let file = el.file;
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/gif';
if (!isJpgOrPng) {
this.$message.error("您只能上传 图片 文件!");
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
this.$message.error('图片大小必须小于2mb!');
}
return isJpgOrPng && isLt2M;
},
pushImg(imgUrl) {
if (!imgUrl) {
return
}
//维护统一的格式
this.imageList.push({
uid: randomUUID(),
name: imgUrl,
status: "done",
url: imgUrl,
response: {
data: imgUrl
},
})
return this.imageList;
},
getList() {
return this.imageList;
},
getFirst() {
for (const info in this.imageList) {
if (!info) {
return info;
}
}
},
}
}
</script>
<style scoped>
</style>
父组件使用
<imgUpload ref="imgUploadHead" v-decorator="['headImage',{ rules: [{ required: true,message: '请上传照片!' }] }]"></imgUpload>
主要针对单图片和多图片进行了封装📦
多图片后台返回和传入的格式:
“http://media.shixun365.com/image/31dc3ee8e4974c4d8257c9c3d1ece085.png”,“http://media.shixun365.com/image/17e2faf8d13e4e2b857cfde6748534b2.png”]
单图片的格式:
http://media.shixun365.com/image/31dc3ee8e4974c4d8257c9c3d1ece085.png

浙公网安备 33010602011771号