上传图片经常需要用到,特此写下一个组件。
<template>
<div>
<el-upload multiple :action="uploadImgUrl" ref="uploadRef" :disabled="disabled" list-type="picture-card"
:on-success="handleUploadSuccess" :before-upload="handleBeforeUpload" :limit="limit" :on-error="handleUploadError"
:on-exceed="handleExceed" name="file" :on-remove="handleRemove" :show-file-list="true" :headers="headers"
v-model:file-list="fileArr" :on-preview="handlePictureCardPreview" :class="{ disabled: fileComputed }">
<el-icon class="avatar-uploader-icon">
<plus />
</el-icon>
</el-upload>
<!-- 上传提示 -->
<div class="el-upload__tip" v-if="showTip">
请上传
<template v-if="fileSize">
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
</template>
<template v-if="fileType">
格式为 <b style="color: #f56c6c">{{ fileType }}</b>
</template>
的图片
</div>
<el-dialog v-model="dialogVisible" title="预览" width="800px" append-to-body>
<img :src="dialogImageUrl" style="display: block; width: 100%; margin: 0 auto" />
</el-dialog>
</div>
</template>
<script setup>
import { ElMessage } from 'element-plus'
import { onMounted, ref } from 'vue';
import { getToken } from '@/utils/token';
const props = defineProps({
// 数量限制
limit: {
type: Number,
default: 1,
},
// 大小限制(MB)
fileSize: {
type: Number,
default: 10,
},
// 文件类型, 例如'png', 'jpg', 'jpeg',字符串,英文逗号隔开
fileType: {
type: String,
default: ".png,.jpg,.jpeg",
},
// 上传的请求头部
headers: {
required: false,
default: { Authorization: `Bearer ${getToken()}` },
},
// 请求的url
uploadImgUrl: {
type: String,
default: `${import.meta.env.VITE_APP_BASE_API}/file/upload`
},
// 是否显示提示
isShowTip: {
type: Boolean,
default: true,
},
// 图片数组
fileList: {
type:Array,
required: false
},
// 照片墙盒子的宽度
fileWidth: {
type: String,
default: '146px'
},
// 照片墙盒子的高度
fileHeight: {
type: String,
default: '146px'
},
disabled: {
type: Boolean,
default: false,
}
})
const emit = defineEmits(['update:fileList'])
const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize));
const dialogVisible = ref(false)
const dialogImageUrl = ref('')
const fileArr = ref([])
// 上传超过数量限制,显示上传按钮
const fileComputed = computed(() => fileArr.value?.length == props.limit)
onMounted(() => {
fileArr.value = props.fileList
})
watch(() => props.fileList,
(newNum, oldNum) => {
fileArr.value = newNum
},
{
// 开启深度监听
deep: true,
})
// 上传前检验文件类型和文件大小
const handleBeforeUpload = (file) => {
// 检验文件类型
let arr = props.fileType.split(',')
if (arr.length) {
let str = '.' + file.name.match(/\.([^.]+)$/)[1].toLowerCase() //匹配格式
const isTypeOk = arr.some((type) => {
if (str.indexOf(type) > -1) return true
return false
})
if (!isTypeOk) {
ElMessage.error(`文件格式不正确, 请上传${props.fileType}格式的图片!`)
return false
}
}
// 检验文件大小
if (props.fileSize) {
const isLt = file.size / 1024 / 1024 < props.fileSize;
if (!isLt) {
ElMessage.error(`上传文件大小不能超过 ${props.fileSize} MB!`)
return false;
}
}
return true
}
// 上传失败的提示
const handleUploadError = () => {
ElMessage.error(`图片上传失败!`)
}
// 上传超过限制
const handleExceed = () => {
ElMessage.error(`上传文件数量不能超过 ${props.limit} 个!`)
}
// 上传成功的回调
const handleUploadSuccess = (response, file, fileList) => {
emit('update:fileList', fileList)
}
// 删除图片的回调
const handleRemove = (file, fileList) => {
emit('update:fileList', fileList)
}
// 预览图片的回调
const handlePictureCardPreview = (file) => {
dialogImageUrl.value = file.url;
dialogVisible.value = true;
}
const uploadRef = ref(null)
defineExpose({
uploadRef,
fileArr
})
</script>
<style lang="scss" scoped>
.disabled :deep(.el-upload--picture-card) {
display: none
}
:deep(.el-upload-list__item-actions) {
width: v-bind('props.fileWidth') !important;
height: v-bind('props.fileHeight') !important;
}
:deep(.el-upload--picture-card) {
width: v-bind('props.fileWidth') !important;
height: v-bind('props.fileHeight') !important;
}
:deep(.el-upload-list__item) {
width: v-bind('props.fileWidth') !important;
height: v-bind('props.fileHeight') !important;
}
</style>
以上props中url必传,其他像大小,数量,文件类型,headers,fileList(回显数组), 照片墙盒子的宽高根据需要传入即可。
举例:
<template>
<div style="margin: 15px;">
<el-button type="primary" @click="open = true">新增</el-button>
<!-- dialogue对话框 -->
<el-dialog v-model="open" title="上传" align-center width="800px" @close="cancelBtn">
<el-form :model="dialogueForm" label-width="100px">
<el-form-item label="图片:">
<imgUpload :limit="2" ref="imgUploadRef" :fileSize="100" :isShowTip="false" :fileList="showImg" @update:fileList="successUploadBtn"
fileWidth="100px" fileHeight="100px"></imgUpload>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="cancelBtn">取消</el-button>
<el-button type="primary" @click="confirmBtn">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
import imgUpload from '@/Components/imgUpload.vue'
const open = ref(false)
const showImg = ref([]) //有编辑按钮回显图片的,只有新增时候fileList可无需传
const imgUploadRef = ref({})
const dialogueForm = ref({})
//上传成功,删除都会调用这个函数,可将要提交的数据在这里操作,如imgPath为接口所传的图片地址
const successUploadBtn = (val) => {
//可以打印一下val,看看哪些是要接口所需要的数据
console.log(val, '瞅瞅')
if (val && val[0] && val[0].response) {
dialogueForm.value.imgPath = val[0].response.data.url
} else {
dialogueForm.value.imgPath = ''
}
}
const cancelBtn = () => {
//清空已上传的文件列表
imgUploadRef.value.uploadRef.clearFiles()
//关闭弹窗
open.value = false
}
const confirmBtn = () => {
/**
* 调接口 。。。。接口(传参) 。。。uploadApi(dialogueForm.value.imgPath)
*/
//清空已上传的文件列表
imgUploadRef.value.uploadRef.clearFiles()
//关闭弹窗
open.value = false
}
</script>