<template>
<div class="image-uploader">
<el-space :size="20" :wrap="multiple">
<template v-if="multiple">
<el-upload v-for="(url, index) in modelValue" drag :key="index" class="uploader-item" :action="action"
:show-file-list="false" :before-upload="beforeUpload" :on-success="(res) => handleSuccess(res, index)"
:disabled="disabled" ref="uploadRefs">
<div v-if="url" class="preview-image" :style="imageStyle" @click.stop="">
<el-image :src="url" fit="cover" :preview-src-list="[url]" :style="imageStyle" />
<div v-if="!disabled" class="image-actions">
<el-button type="primary" link @click.stop="triggerUpload(index)">重新上传</el-button>
<el-button type="danger" link @click.stop="handleDelete(index)">删除</el-button>
</div>
</div>
<div v-else class="upload-placeholder" :style="imageStyle">
<icon-ep-plus />
<div class="text-sm mt-2">{{ placeholders[index] || '上传图片' }}</div>
</div>
</el-upload>
<el-upload v-if="showAddButton" class="uploader-item" drag :action="action" :show-file-list="false" :before-upload="beforeUpload"
:on-success="handleNewUpload" :disabled="disabled">
<div class="upload-placeholder" :style="imageStyle">
<icon-ep-plus />
<div class="text-sm mt-2">添加图片</div>
</div>
</el-upload>
</template>
<el-upload v-else class="uploader-item" drag :action="action" :show-file-list="false" :before-upload="beforeUpload"
:on-success="handleSingleSuccess" :disabled="disabled" ref="singleUploadRef">
<div v-if="modelValue" class="preview-image" :style="imageStyle" @click.stop="">
<el-image :src="modelValue" fit="cover" :preview-src-list="[modelValue]" :style="imageStyle" />
<div v-if="!disabled" class="image-actions">
<el-button type="primary" link @click.stop="triggerSingleUpload">重新上传</el-button>
<el-button type="danger" link @click.stop="handleDeleteSingle">删除</el-button>
</div>
</div>
<div v-else class="upload-placeholder" :style="imageStyle">
<icon-ep-plus />
<div class="text-sm mt-2">{{ placeholder }}</div>
</div>
</el-upload>
</el-space>
<div class="el-upload__tip mt-1" v-if="!isTip">支持 jpg/png 格式,大小不超过 10MB</div>
</div>
</template>
<script setup>
import { computed, ref } from 'vue'
import { ElMessage } from 'element-plus'
import { getUploadUrl } from '#/utils/config'
const action = computed(() => getUploadUrl())
const props = defineProps({
modelValue: {
type: [String, Array],
default: () => ''
},
multiple: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
// action: {
// type: String,
// default: UploadUrl
// },
width: {
type: [String, Number],
default: 150
},
height: {
type: [String, Number],
default: 150
},
placeholder: {
type: String,
default: '上传图片'
},
placeholders: {
type: Array,
default: () => []
},
type: {
type: String,
default: ''
},
isTip: {
type: Boolean,
default: false
},
limit: {
type: [String, Number],
default: ''
}
})
const emit = defineEmits(['update:modelValue', 'uploadImgCallback'])
const imageStyle = computed(() => {
const width = typeof props.width === 'number' ? `${props.width}px` : props.width
const height = typeof props.height === 'number' ? `${props.height}px` : props.height
return {
width,
height
}
})
// 计算属性:是否显示添加按钮
const showAddButton = computed(() => {
// 如果设置了limit,则根据当前数量和limit比较
if (props.limit) {
return Array.isArray(props.modelValue) && props.modelValue.length < Number(props.limit);
}
// 如果没有设置limit,则始终显示添加按钮
return true;
});
// 文件上传前校验
const beforeUpload = (file) => {
const isImage = file.type.startsWith('image/')
if (!isImage) {
ElMessage.error('只能上传图片文件!')
return false
}
const isLt2M = file.size / 1024 / 1024 < 10
if (!isLt2M) {
ElMessage.error('图片大小不能超过 2MB!')
return false
}
return true
}
// 单图片上传成功
const handleSingleSuccess = (res) => {
emit('update:modelValue', `${res.data.host}/${res.data.url}`);
if (props.type == 'businessLicense') {
emit('uploadImgCallback', `${res.data.host}/${res.data.url}`)
}
}
// 多图片上传成功
const handleSuccess = (res, index) => {
const newValue = [...props.modelValue]
newValue[index] = `${res.data.host}/${res.data.url}`
emit('update:modelValue', newValue)
if (props.type == 'idCardImages') {
emit('uploadImgCallback', `${res.data.host}/${res.data.url}`)
}
}
// 新增图片上传成功
const handleNewUpload = (res) => {
const newValue = Array.isArray(props.modelValue) ? [...props.modelValue] : []
newValue.push(`${res.data.host}/${res.data.url}`)
emit('update:modelValue', newValue)
if (props.type === 'idCardImages') {
emit('uploadImgCallback', `${res.data.host}/${res.data.url}`)
}
}
// 删除多图片中的某一张
const handleDelete = (index) => {
const newValue = [...props.modelValue]
newValue.splice(index, 1)
emit('update:modelValue', newValue)
}
// 删除单图片
const handleDeleteSingle = () => {
emit('update:modelValue', '')
}
// 添加ref用于获取上传组件实例
const uploadRefs = ref()
const singleUploadRef = ref(null)
// 触发多图片中某一项的上传
const triggerUpload = (index) => {
if (Array.isArray(uploadRefs.value) && uploadRefs.value[index]) {
uploadRefs.value[index].$el.querySelector('input').click()
}
}
// 触发单图片上传
const triggerSingleUpload = () => {
if (singleUploadRef.value) {
singleUploadRef.value.$el.querySelector('input').click()
}
}
</script>
<style lang="scss" scoped>
.image-uploader {
.uploader-item {
:deep(.el-upload) {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
transition: border-color 0.3s;
&:hover {
border-color: var(--el-color-primary);
}
}
}
.preview-image {
position: relative;
.image-actions {
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 32px;
background: rgba(0, 0, 0, 0.6);
display: flex;
justify-content: center;
align-items: center;
opacity: 0;
transition: opacity 0.3s;
}
&:hover .image-actions {
opacity: 1;
}
}
:deep(.el-upload-dragger) {
// width: 150px;
// height: 150px;
padding: 0 !important;
display: flex;
align-items: center;
justify-content: center;
}
.upload-placeholder {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #8c939d;
}
}
</style>
可不改变顺序重新上传
可预览图片
使用方法
<uploadImages v-model="formData.businessLicense" type="businessLicense" @uploadImgCallback="uploadImgCallback"
:width="120" :height="120" placeholder="上传营业执照" :disabled="disabled" />
width 和 height 设置高度
multiple 允许上传多张
limit 设置最多上传几张
uploadImgCallback 上传成功回调 可不写,有需要可以写
isTip 设置提示文字是否显示
&spm=1001.2101.3001.5002&articleId=149446895&d=1&t=3&u=dd7cc44b4629442ba152043944c2762d)
3060

被折叠的 条评论
为什么被折叠?



