【antd Vue】封装upload图片上传组件(返回Base64)

时间:2023-03-10 03:44:20
【antd Vue】封装upload图片上传组件(返回Base64)

最近需要把上传的图片信息存储到数据库,以base64的方式,需要重新封装一下antd的upload组件

1. 使用方法

引入组件然后配置一下即可使用,配置项包括

  • defaultImageList,需要回显的图片(必传),[ url1, url2 ]
  • fileTypeList ,文件格式(可选),默认不做限制
  • limitSize ,单个图片大小限制(可选),单位MB
  • limitNum ,上传图片个数限制(可选),默认200个
  • multiple ,是否可以多选(可选),默认否
  • disabled ,是否禁用(可选),默认否
  1. 引用组件
<template>
<div>
<b-upload-image-base64 ref="bUploadImageBase64" :limitNum="1" @change="change" :defaultImageList="data" />
</div>
</template>
<script>
import bUploadImageBase64 from '@/components/BUploadImageBase64'
export default {
components: {
bUploadImageBase64
},
data() {
return {
data: ['https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'],
defaultImageList: []
};
},
methods: {
change(e) {
console.log('e', e)
}
},
};
</script>
<style> </style>
  1. 组件
<template>
<div class="clearfix">
<a-upload
:beforeUpload="beforeImageUpload"
list-type="picture-card"
:file-list="imageList"
:multiple="multiple"
:disabled="disabled"
@change="handleImageChange"
@preview="handlePreview"
:custom-request="customRequest"
>
<div v-if="imageList.length < limitNum && !disabled">
<a-icon type="plus"/>
<div class="ant-upload-text">上传</div>
</div>
</a-upload>
<a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel">
<img alt="example" style="width: 100%" :src="previewImage"/>
</a-modal>
</div>
</template>
<script>
function getBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => resolve(reader.result)
reader.onerror = error => reject(error)
})
} export default {
props: {
defaultImageList: {
type: Array,
default: function() {
return []
},
required: true
},
fileTypeList: {
type: Array,
default: function() {
return []
},
required: false
},
limitSize: {
type: Number,
default: 5,
required: false
},
limitNum: {
type: Number,
default: 20,
required: false
},
multiple: {
type: Boolean,
default: false,
required: false
},
disabled: {
type: Boolean,
default: false,
required: false
}
},
data() {
return {
previewVisible: false,
previewImage: '',
imageList: []
}
},
watch: {
defaultImageList(newVal) {
this.imageList = this.handleData(newVal)
}
},
created() {
this.imageList = this.handleData(this.defaultImageList)
},
methods: {
// ---------------------------------------------img--start
beforeImageUpload(file) {
return new Promise((resolve, reject) => {
if (!this.fileTypeList) {
const index = this.fileTypeList.indexOf(file.type)
if (index > 0) {
this.$message.error(`您只能上传${this.fileTypeList[index]}文件`)
}
}
const limitSize = file.size / 1024 / 1024 < this.limitSize
if (!limitSize) {
this.$message.error(`文件大小不能大于${this.limitSize}MB`)
return reject(new Error(`文件大小不能大于${this.limitSize}MB`))
}
return resolve(true)
})
},
async handlePreview(file) {
if (!file.url && !file.preview) {
file.preview = await getBase64(file.originFileObj)
}
this.previewImage = file.url || file.preview
this.previewVisible = true
},
handleCancel() {
this.previewVisible = false
},
customRequest({ action, file, onSuccess, onError, onProgress }) {
new Promise(resolve => {
const fileReader = new FileReader()
fileReader.readAsDataURL(file)
fileReader.onload = () => {
let index = {
uid: this.genId(5),
name: file.name,
status: 'done',
url: fileReader.result
}
this.imageList = [...this.imageList.filter(item => item.status === 'done'), index]
this.$message.success('文件上传成功!')
this.handleChange()
resolve(fileReader.result)
}
})
},
handleImageChange(info) {
let fileList = [...info.fileList]
this.imageList = fileList
this.handleChange()
},
handleChange() {
let index = this.imageList.filter(item => item.url).map(item => {
return item.url
})
this.$emit('change', index ? index : [])
},
genId(length) {
return Number(Math.random().toString().substr(3, length) + Date.now()).toString(36)
},
handleData (list) {
return list.map(item => {
let index = this.genId(5)
return {
uid: index,
name: index,
status: 'done',
url: item
}
})
}
// ---------------------------------------------img--end
}
}
</script>
<style>
/* you can make up upload button and sample style by using stylesheets */
.ant-upload-select-picture-card i {
font-size: 32px;
color: #999;
} .ant-upload-select-picture-card .ant-upload-text {
margin-top: 8px;
color: #666;
}
</style>

2. 封装遇到的坑

因为是自己实现上传逻辑需要使用属性:custom-request="customRequest"

组件的运行顺序是beforeImageUpload->customRequest

  1. 一开始的校验需要写在beforeImageUpload中,主要是验证文件格式,文件大小
  2. 然后进入自定义的上传逻辑,这里主要是读取图片为base64,然后放入回显的数组中,这样组件就可以显示上传的图片了,此时还需要回调base64
  3. handleChange方法主要是删除图片使用,需要过滤出非undefined的,剩余的图片并回传base64