背景:
在项目开发,需要上传图片,一张或者多张。当上传1张图片时,upload组件有一张图片时,组件自带的disable=true设置为true禁用上传,就不会触发上传接口了,但是还是可以点开图片进行选择,【优化为:已经上传一张,就不可以触发选择,即不选择图片也不触发上传接口】;当一张图片的时候,通过改变upload组件的css样式隐藏组件,使用:class=" 'isActive' "通过变量控制upload组件的显示与否;当上传多张图片的时候,同上传1张的逻辑一样,只是数量不同。
一、上传1张图片
实现效果:
结果分析:
通过组件的limit='1'属性设置为1张,并且组件的disable属性变成了true。这个时候实现的效果是:当成功上传一张图片,并且上传组件已经被禁用,不能够触发选择图片的弹框。这已经能够实现上传单张的效果了,但是项目要求,上传一张还想重新删除、再上传,这时候发现已经上传的图片只有预览,删除按钮不见了,这个时候需要想办法把删除按钮显示出来。
解决思路:
类似于自定义一张icon的绝对定位,让它显示在图片上面。
核心代码:
解决办法:
官方文档:点击访问官网
封装的组件代码:
<el-upload
list-type="picture-card"
:limit="1"
:file-list="upImgState.fileList"
:style="{
width: item.width || '10vw',
height: item.width || '10vw',
}"
:action="item.option.importUrl"
:data="item.option.uploadParames"
:show-file-list="true"
:headers="{ Authorization: store.userInfo.token }"
:on-success="(info) => uploadSingleImg('success', info, item)"
:on-error="(info) => uploadSingleImg('error', info)"
:before-upload="beforeUploadSingleImg"
:before-remove="
(info) => beforeRemoveSingleImg('remove', info, item)
"
:on-preview="handlePictureCardPreview"
accept="image/jpeg,image/png"
:disabled="
upImgState.fileList.length
? true
: false
"
>
<el-icon class="avatar-uploader-icon">
<Plus />
</el-icon>
<template #file="{ file }">
<div>
<img
class="el-upload-list__item-thumbnail"
:src="file.url"
alt=""
/>
<span class="el-upload-list__item-actions">
<span
class="el-upload-list__item-preview"
@click="handlePictureCardPreview(file)"
>
<el-icon><zoom-in /></el-icon>
</span>
<span
class="el-upload-list__item-delete"
@click="beforeRemoveSingleImg('remove', file, item)"
>
<el-icon><Delete /></el-icon>
</span>
</span>
</div>
</template>
</el-upload>
<el-dialog v-model="upImgState.dialogVisible">
<img
:src="upImgState.dialogImageUrl"
alt="Preview Image"
style="width: 100%"
/>
</el-dialog>
<script>
const uploadSingleImg = (state, info, item) => {
if (state === "success") {
const { data: resData } = info;
item.getRowInfo(resData);
upImgState.dialogImageUrl = BASEUrl + "/file/" + resData;
const _fileList = upImgState.fileList || [];
_fileList.unshift({ url: upImgState.dialogImageUrl });
upImgState.fileList = _fileList;
}
ElMessage({
type: state,
message: `单个文件上传${state === "success" ? "成功" : "失败"}`,
});
};
const beforeUploadSingleImg = (rawFile) => {
if (!rawFile) return false;
if (rawFile.type !== "image/jpeg" && rawFile.type !== "image/png") {
ElMessage.error("文件类型须为图片格式!");
return false;
} else if (rawFile.size / 1024 / 1024 > 10) {
ElMessage.error("文件大小须小于10MB!");
return false;
}
return true;
};
const beforeRemoveSingleImg = (state, info, item) => {
if (state === "remove") {
console.log("info", info);
const _fileName = info.url.split("/")[info.url.split("/").length - 1];
const _fileType = item.option.uploadParames.fileType;
item.removeImg({
title: "删除图片",
fileName: _fileName,
fileType: _fileType,
});
upImgState.fileList = [];
}
return true;
};
const upImgState = reactive({
dialogVisible: false, //预览弹框显示与否
dialogImageUrl: "",
fileList: [],
});
const handlePictureCardPreview = (file) => {
upImgState.dialogImageUrl = file.url || BASEUrl + file.url;
upImgState.dialogVisible = true;
};
</script>
如何使用封装的组件:
//没有写完,只只是个传参示例
{
type: "uploadSingleImg",
label: "渡船图片",
key: "photo",
option: {
uploadParames: {
fileType: 2,
},
img_bg: "table/upload.png",
info: "upload",
text: "上传",
importUrl: BASEUrl + "/data/file/upload",
},
width: "100%",
getRowInfo: (data) => {
console.log("上传图片的结果", data);
state.formItemsVal.photo = data;
},
removeImg: (data) => {
console.log("删除图片的结果", data);
api.fileApi
.deleteFile({ fileName: data.fileName, fileType: data.fileType })
.then((res) => {
if (res.status === 200 && res.data.code === 200) {
ElMessage({
type: "success",
message: "删除成功",
});
} else {
ElMessage({
type: "error",
message: res.data.message || "删除失败",
});
}
})
.catch((err) => {
console.log(err);
});
},
},
备注:
上传图片这里我选用的是自动上传,所以当我选中一张图片就会触发上传接口,根据接口就会返回一个{},包括但不限于:图片的相对路径、图片的名称等等。
这里需要注意的是图片相对路径,要显示在界面上,需要图片代理,最好使用BASEUrl,根据 const BASEUrl = import.meta.env.VITE_USER_NODE_ENV === 'development' ?判断开发环境还是生产环境,进行拼接访问路径。
图片新增,需要拼接访问前缀【也可以不要,但是要预览就需要】;图片复现,需要拼接访问前缀,图片编辑接口,需要去掉访问前缀。
图片删除接口,需要对应的文件名+文件类型,依据接口文档。
图片回显,需要拼接前缀:
编辑操作:
删除操作:
图片删除再上传:
解决方式:
在调删除接口的时候,正确传参。核心代码如下:
二、上传多张图片
效果展示:
上传多张图片的时候,最后一张图片也没有删除按钮,最后一张只有预览按钮:
解决方式:
同一张图片一样:
三、上传一张图片后,隐藏upload组件
效果实现:
核心代码:
<el-upload
:auto-upload="false"
list-type="picture-card"
:on-preview="handlePictureCardPreview"
:on-change="uploadSingleImg"
:limit="5"
:file-list="upImgState.fileList"
:class="upImgState.fileList.length !== 0 ? 'isHidden' : ''"
>
<el-icon v-if="upImgState.fileList.length == 0">
<Plus />
</el-icon>
</el-upload>
<el-dialog v-model="upImgState.dialogVisible">
<img
:src="upImgState.dialogImageUrl"
alt="Preview Image"
style="width: 100%"
/>
</el-dialog>
//css样式
.isHidden{
.el-upload--picture-card {
display: none;
}
:deep(.el-upload--picture-card) {
display: none;
}
}
写在最后:
两种方式限制上传的数量,当限制1张的时候,使用upload组件自带的disable属性禁用组件;使用动态class绑定一个变量控制是否显示upload上传框。