antd-design-vue的upload组件上传的使用并不是很友好,需要需要定义一个数组对象来展示图片,二次封装,可以使得仅需要使用少量代码就可以调用,配合之前封装好的图片预览插件juejin.cn/post/743178… ,非常完美
使用方法:
import UploadImg from '@/components/upload/UploadImg.vue'
<UploadImg v-model="form.imgList"></UploadImg>
1:props 参数
继承antd上传组件所有参数,扩展自定义参数
| 属性 | 描述 | 默认 |
|---|---|---|
| v-model | Aarry[string] | 初始化的值 格式为:必须为字符串数组 如:['httpxxx', 'httpxxx'] |
| fromat | Aarry[string] | 格式 默认['.png', '.jpg', '.gif', '.jpeg', '.apng'] |
| size | number | 图片大小(M) 默认10M |
2:事件回调函数
| 属性 | 描述 | 默认 |
|---|---|---|
| upload-success | 上传图片成功 | (file, imgList)=> {} |
| upload-error | 上传图片失败 | (file, imgList)=> {} |
<template>
<a-upload-dragger
v-bind="$attrs"
:file-list="fileList"
name="file"
@change="handleChange"
:accept="format.join(',')"
list-type="picture"
@preview="handlePreview"
:beforeUpload="handleBeforeUpload"
@remove="handleRemove"
>
<div class="ant-upload">
<div>
<UploadOutlined style="font-size: 32px" />
<div>点击或者拖拽导入</div>
<div>格式为{{ format.join('、') }},单张不超过{{ size }}M</div>
</div>
</div>
</a-upload-dragger>
</template>
<script setup>
/**
图片上传组件
使用方法:
import PoUploadImg from '@/poComponents/upload/PoUploadImg.vue'
<PoUploadImg v-model="form.imgList"></PoUploadImg>
1:props 参数
继承antd上传组件所有参数,扩展自定义参数
v-model Aarry[string] 初始化的值 格式为:必须为字符串数组 如:['httpxxx', 'httpxxx']
fromat Aarry[string] 格式 默认['.png', '.jpg', '.gif', '.jpeg', '.apng']
size number 图片大小(M) 默认10M
2:事件回调函数
upload-success 上传图片成功 (file, imgList)=> {}
upload-error 上传图片失败 (file, imgList)=> {}
*/
import { UploadOutlined } from '@ant-design/icons-vue'
import { UploadDragger as AUploadDragger, message } from 'ant-design-vue'
import { ref, useAttrs, watch } from 'vue'
import usePreviewImg from './usePreviewImage'
import { couponUpload } from '@/service/api'
import errorImg from '@/assets/icon/error.png'
const attr = useAttrs()
const previewImage = usePreviewImg()
const props = defineProps({
// 格式
format: {
type: Array,
default() {
return ['.png', '.jpg', '.gif', '.jpeg', '.apng']
}
},
// 大小,10M
size: {
type: Number,
default: 10
},
// 传入的值,必须为字符串数组 如:['httpxxx', 'httpxxx']
modelValue: {
type: Array,
required: true,
default() {
return []
}
}
})
const emit = defineEmits(['update:modelValue', 'upload-success', 'upload-error'])
const fileList = ref([
// {
// status: 'uploading',
// thumbUrl: 'https://xxx',
// uid: 'vc-upload-1730864018078-6',
// url: 'xxx.png'
// }
])
watch(
() => props.modelValue,
(value) => {
// 如果内容没有发生变化,则不更新内容
let hasUplaod = false
const oldValue = fileList.value.map((item) => {
if (item.status === 'done') {
return item.url
} else if (item.status === 'uploading' || item.status === 'error') {
hasUplaod = true
}
})
// 如果url数量没有变化或者有正在上传的图片或者出错,不更新fileList,只有在父组件传值进来的时候,才会改变
if (value.join(',') === oldValue.join(',') || hasUplaod) return
// 需要清空内部的值
fileList.value = []
value.forEach((val, index) => {
// 校验
if (typeof val !== 'string') {
throw new Error('图片上传组件:v-model的数据必须为字符串数组!')
}
const item = {
thumbUrl: val,
url: val,
status: 'done',
uid: 'uid' + index
}
fileList.value.push(item)
})
},
{ immediate: true }
)
const emitDate = () => {
const list = []
fileList.value.forEach((item) => {
if (item.status === 'done') {
list.push(item.url)
}
})
return list
}
// 自己接管上传的处理
const handleBeforeUpload = () => {
return false
}
// 图片移除
const handleRemove = (file) => {
const index = fileList.value.findIndex((item) => item.uid === file.uid)
fileList.value.splice(index, 1)
emit('update:modelValue', emitDate())
}
// 内容发生改变
const handleChange = (info) => {
const file = info.file
const status = info.file.status
if (file.size > 1024 * 1024 * props.size) {
message.error(`文件大小不能超过${props.size}M`)
return
} else if (attr.maxCount && fileList.value.length >= attr.maxCount) {
message.error(`图片数量不能超过${attr.maxCount}张`)
return
}
if (!status) {
imgageUploadFn(file)
}
}
// 上传图片函数
const imgageUploadFn = (file) => {
const item = {
uid: file.uid,
status: 'uploading'
}
fileList.value.unshift(item)
const formData = new FormData()
formData.append('file', file)
// 上传接口调用
couponUpload(formData)
.then((res) => {
const item = fileList.value.find((sub) => sub.uid === file.uid)
item.thumbUrl = res
item.url = res
item.status = 'done'
const list = emitDate()
emit('update:modelValue', list)
emit('upload-success', file, list)
})
.catch(() => {
const item = fileList.value.find((sub) => sub.uid === file.uid)
item.thumbUrl = errorImg
item.url = errorImg
item.status = 'error'
emit('upload-error', file, emitDate())
})
}
// 预览
const handlePreview = (file) => {
const index = fileList.value.findIndex((item) => item.uid === file.uid)
previewImage.show({
list: fileList.value.map((sub) => sub.thumbUrl),
current: index
})
}
</script>
<style lang="less" scoped>
.ant-upload {
height: 118px;
display: flex;
align-items: center;
justify-content: center;
color: #286043;
}
</style>