el-upload实现上传图片/pdf,回显图片/pdf功能。
el-upload实现上传图片/pdf,回显图片/pdf功能。
功能背景:上传图片和查看图片要在一个页面。
如何回显当前行数据已上传的文件?
答:把请求获取的数据赋值给绑定的fileList
<el-upload
:action="url"
multiple
list-type="picture-card"
:on-preview="handlePictureCardPreview"
:on-success="successFirstImg"
:on-remove="removeFirstImg"
:file-list="firstImgList"
>
<i class="el-icon-plus"></i>
</el-upload>
this.firstImgList = this.processImageList(res, 1);
文件上传成功后,绑定的filelist变量的length会自动增加一个吗?
答:不会,需要赋值,on-sucess绑定的事件参数filelist 赋值给data中定义的filelist
successFirstImg(res, file, fileList) {
this.$message.success(res.msg);
this.firstImgList = fileList;
},
如何把回显的文件和操作上传的文件一起提交给后台
答案:回显的文件中没有response对象,上传成功的文件会包含response对象,把两种数据提取出来组合在一起就可以了
如何显示和回显pdf文件,
在 HTML 中,<img>
标签主要用于显示图像文件,如 JPEG、PNG、GIF 等。PDF 文件并不是图像文件,因此 <img>
标签无法直接显示 PDF 内容。
el-upload内置的是img标签所以不支持pdf,
1.第一种方案用的iframe标签
缺点: iframe加载很慢,最少得等40秒才能出来,
2.第二种方案用的embed标签加载很快,
使用embed 或object标签:
- 这些标签可以嵌入 PDF 文件,并且大多数现代浏览器都支持这些标签来显示 PDF。
<embed src="path/to/your/file.pdf" type="application/pdf" width="600" height="500">
<object data="path/to/your/file.pdf" type="application/pdf" width="600" height="500">
<p>您的浏览器不支持 PDF 显示。</p>
</object>
总结:用embed 或 object 标签更合适。
其中重要的是,el-upload中用插槽以后,会覆盖组件本身封装的结构,所以on-remove,和on-preview绑定的事件就不生效了,得自己定义
removeSecondImg(file) {
let uploadFiles = this.$refs.elUpload.uploadFiles;
let index = uploadFiles.findIndex((item) => {
return item.uid == file.uid;
});
console.log("🚀 ~ index ~ index:", index);
uploadFiles.splice(index, 1);
this.secondImgList = uploadFiles;
},
上传文件filelist中每个文件会有一个uid字段,用uid找出要删除的文件,进行删除。
效果取下:
预览PDF:
完整代码如下:
<template>
<div class="dialogBox">
<el-dialog
:title="title"
:visible.sync="visible"
:close-on-click-modal="false"
:width="width"
@close="cancel"
>
<div style="display: flex; font-size: 16px">
<div style="width: 33.3%">
<ImgTitle :title="firstTitle" />
<div class="imgCenter">
<el-upload
:action="url"
multiple
list-type="picture-card"
:on-preview="handlePictureCardPreview"
:on-success="successFirstImg"
:on-remove="removeFirstImg"
:file-list="firstImgList"
>
<i class="el-icon-plus"></i>
</el-upload>
</div>
</div>
<div style="width: 33.3%">
<ImgTitle :title="secondTitle" />
<div class="imgCenter">
<el-upload
ref="elUpload"
:action="url"
multiple
list-type="picture-card"
:on-success="successSecondImg"
:file-list="secondImgList"
>
<i class="el-icon-plus"></i>
<div slot="file" slot-scope="{ file }">
<embed
v-if="isPdfFile(file)"
:src="file.url"
width="100%"
></embed>
<img
v-else
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)
"
>
<i class="el-icon-zoom-in"></i>
</span>
<span
v-if="!disabled"
class="el-upload-list__item-delete"
@click="removeSecondImg(file)"
>
<i class="el-icon-delete"></i>
</span>
</span>
</div>
</el-upload>
</div>
</div>
<div style="width: 33.3%">
<ImgTitle :title="thirdTitle" />
<div class="imgCenter">
<el-upload
:action="url"
multiple
list-type="picture-card"
:on-preview="handlePictureCardPreview"
:on-success="successThirdImg"
:on-remove="removeThirdImg"
:file-list="thirdImgList"
>
<i class="el-icon-plus"></i>
</el-upload>
</div>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="submitFn" v-preventReClick
>确定</el-button
>
</span>
</el-dialog>
<el-dialog :visible.sync="dialogVisible">
<embed width="100%" height="500" :src="dialogImageUrl" v-if='dialogImageUrl.endsWith(".pdf")'></embed>
<img width="100%" :src="dialogImageUrl" alt="" v-else/>
</el-dialog>
</div>
</template>
<script>
import { uploadImg, saveImg, selectPileImgs } from "_config/url.js";
import ImgTitle from "./ImgTitle";
export default {
components: {
ImgTitle,
},
data() {
return {
title: "上传图片",
visible: false,
url: uploadImg,
width: "800px",
firstTitle: "铭牌照片",
secondTitle: "第三方检测报告",
thirdTitle: "枪口数量图片",
dialogVisible: false,
dialogImageUrl: "",
params: null,
firstImgList: [],
secondImgList: [],
thirdImgList: [],
};
},
methods: {
isPdfFile(file) {
if (!file.url && !file.name) return false;
const pdfRegex = /\.pdf$/i;
return (
(file.url && pdfRegex.test(file.url)) ||
(file.name && pdfRegex.test(file.name))
);
},
async show(params) {
console.log("🚀 ~ show ~ params:", params);
this.params = params;
await this.getInfo();
this.visible = true;
},
// 预览图片
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
},
// 移除图片
removeFirstImg(file, fileList) {
this.firstImgList = fileList;
},
removeSecondImg(file) {
let uploadFiles = this.$refs.elUpload.uploadFiles;
let index = uploadFiles.findIndex((item) => {
return item.uid == file.uid;
});
console.log("🚀 ~ index ~ index:", index);
uploadFiles.splice(index, 1);
this.secondImgList = uploadFiles;
},
removeThirdImg(file, fileList) {
this.thirdImgList = fileList;
},
// 上传图片成功
successFirstImg(res, file, fileList) {
this.$message.success(res.msg);
this.firstImgList = fileList;
},
successSecondImg(res, file, fileList) {
this.$message.success(res.msg);
this.secondImgList = fileList;
},
successThirdImg(res, file, fileList) {
this.$message.success(res.msg);
this.thirdImgList = fileList;
},
getList(fileList, fileListName) {
console.log("🚀 ~ getList ~ fileList:", fileList);
const imgTypeMap = {
firstImgList: 1,
secondImgList: 2,
thirdImgList: 3,
};
let imgType = imgTypeMap[fileListName];
if (fileList.length > 0) {
// 上传的图片列表
let submitImgList = fileList
.filter((i) => i.response && i.response.msg == "上传成功")
.map((j, index) => {
return {
imgUrl: j.response.imgUrl,
imgType,
};
});
// 已上传的图片列表回显
let echoImgList = fileList
.filter((i) => !i.response && i.sequence)
.map((j, index) => {
return {
imgUrl: this.extractPathFromUrl(j.url),
imgType: j.imgType,
};
});
console.log("🚀 ~ getList ~ echoImgList :", echoImgList);
//图片列表合并添加排序
this[fileListName] = [...echoImgList, ...submitImgList].map(
(i, index) => {
return {
imgUrl: i.imgUrl,
imgType: i.imgType,
code: this.params[0].code,
sequence: index + 1,
};
}
);
}
console.log(
"🚀 ~ getList ~ this.firstImgList;:",
this.firstImgList
);
console.log(
"🚀 ~ getList ~ this.secondImgList:",
this.secondImgList
);
console.log(
"🚀 ~ getList ~ this.thirdImgList:",
this.thirdImgList
);
},
// 提交上传
async submitFn() {
this.getList(this.firstImgList, "firstImgList");
this.getList(this.secondImgList, "secondImgList");
this.getList(this.thirdImgList, "thirdImgList");
let imgList = [
...this.firstImgList,
...this.secondImgList,
...this.thirdImgList,
];
console.log("🚀 ~ submitFn ~ imgList:", imgList);
try {
let res = await this.$post(saveImg, imgList);
if (res.status == 1) {
this.$message.success(res.msg);
} else {
this.$message.error(res.msg);
}
this.cancel();
} catch (err) {
console.log(err);
}
},
// 查看图片
async getInfo() {
try {
let res = await this.$post(selectPileImgs, {
code: this.params[0].code,
});
console.log("🚀 ~ getInfo ~ res :", res);
if (res) {
this.firstImgList = this.processImageList(res, 1);
this.secondImgList = this.processImageList(res, 2);
this.thirdImgList = this.processImageList(res, 3);
} else {
this.firstImgList = [];
this.secondImgList = [];
this.thirdImgList = [];
}
} catch (err) {
console.log(err);
}
},
cancel() {
this.visible = false;
this.dialogVisible = false;
this.dialogImageUrl = "";
this.firstImgList = [];
this.secondImgList = [];
this.thirdImgList = [];
this.params = null;
this.$emit("close");
},
// 回显时处理图片列表
//根据imgType分类,根据sequence排序
processImageList(res, imgType) {
return res
.filter((i) => i.img_type === imgType)
.map((i) => ({
url: this.PIC_URL + i.url,
sequence: i.sequence,
imgType: i.img_type,
}))
.sort((a, b) => a.sequence - b.sequence);
},
// 图片路径处理, 去掉前缀PIC_URL
extractPathFromUrl(url) {
if (url.startsWith(this.PIC_URL)) {
return url.substring(this.PIC_URL.length);
}
return "";
},
},
};
</script>
<style scoped lang="less">
/deep/ .el-upload-list__item-name {
overflow: auto;
white-space: normal;
}
/deep/ .el-image__inner {
width: 180px;
height: 180px;
border: 1px solid #00000080;
margin-bottom: 3px;
border-radius: 10px;
}
.imgCenter {
margin: 0 auto;
text-align: center;
}
.img {
width: 261px;
height: 187px;
display: block;
margin: 20px auto;
}
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409eff;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
width: 178px;
height: 178px;
display: block;
}
</style>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现