现有如下需求
1、用户可以选择多张图片,点击按钮完成上传
2、向后台发送的数据必须为base64位编码的格式
3、图片名以下标命名
4、接口只支持单张图片的上传,上传成功后返回一个线上的图片地址
5、最终拿到一个长度为选择的图片的数量,内容是每张图片返回的线上图片地址的一个数组
实现思路
1、选中图片后即时的将选择的图片转换为base64存入一个数组中,删除该图片时也在数组中将该图片删除,始终保证存放base64的数组和已选择的图片相对应
2、点击上传按钮利用 for of 遍历 base64 数组,在每一遍的循环中请求上传图片的接口,传递当前图片的base64编码和当前循环的下标
3、等待接口返回结果,将返回的结果存入一个数组中,在进行下一次循环
4、循环完毕后拿到存放结果的数组
从思路上看我们需要重点关注的就是如何处理调用接口返回结果后再进行下一次循环,并如何在循环外边拿到返回的数组
开始撸码
<template>
<div class="about">
<!--
action:必填,图片上传地址,我们为异步上传因此此处用井号代替
on-preview:点击文件列表中已上传的文件时的钩子
on-remove:文件列表移除文件时的钩子
auto-upload:是否在选取文件后立即进行上传
multiple:是否支持多选文件
limit:最大允许上传个数
on-change:文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用
on-exceed:文件超出个数限制时的钩子
accept:接受上传的文件类型(thumbnail-mode 模式下此参数无效)
-->
<el-upload
action="#"
list-type="picture-card"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove"
:auto-upload="false"
:multiple="true"
:limit="5"
:on-change="changeIamge"
:on-exceed="onExceed"
accept="image/*"
>
<i class="el-icon-plus"></i>
{{base64ImageData.length}}/5
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" alt />
</el-dialog>
<el-button type="primary" @click="uploadImg">
点击上传
<i class="el-icon-upload el-icon--right"></i>
</el-button>
<span>{{message}}</span>
</div>
</template>
<script>
import http from "../util/http";
export default {
data() {
return {
// 弹出图片大图路径
dialogImageUrl: "",
dialogVisible: false,
// 存放base64位编码的图片集合
base64ImageData: [],
message: "当前图片尚未上传",
};
},
methods: {
// 删除图片触发
handleRemove(file, fileList) {
// 删除存放base64位编码的图片集合
let removeIndex = this.base64ImageData.findIndex(
(item) => file.uid === item.uid
);
// 利用findIndex获取当前删除的图片下标
this.base64ImageData.splice(removeIndex, 1);
},
// 查看图片大图
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
},
// 超出最大上传数量触发
onExceed() {
this.$alert("超出最大上传数量");
},
// 选择图片时触发
changeIamge(file, fileList) {
// 此处调用是选择图片就立即转换为base64
this.getBase64(file.raw).then((res) => {
this.base64ImageData.push({
base64Code: res,
uid: file.uid,
});
});
},
// 将选择的图片处理成为Base64
getBase64(file) {
// 返回Promise格式
return new Promise((resolve, reject) => {
let reader = new FileReader();
let imgResult = "";
reader.readAsDataURL(file);
reader.onload = () => {
imgResult = reader.result;
};
// 成功返回
reader.onloadend = () => {
resolve(imgResult);
};
// 失败返回
reader.onerror = () => {
reject(error);
};
});
},
// 点击上传按钮
async uploadImg() {
// 数组非空校验
if (this.base64ImageData.length === 0) {
this.$alert("请选择图片再进行上传操作");
return;
}
// 存放线上的图片路径集合
let resultImage = [];
// 利用for of 遍历依次上传图片 entries()可以解决for of 遍历获取不到下标的问题
for (const [index, item] of this.base64ImageData.entries()) {
let data = {
imgName: `图片_0${index + 1}`,
baseCode: item.base64Code,
fileName: "jpg",
};
// axync await 等待当前循环图片上传完成在进行下一张图片的上传
let resImage = await this.uploadPostFun(data);
// 此状态吗和后台商定,成功会返回六个零
if (resImage.code === "000000") {
resultImage.push(resImage.result.imgUrl);
this.message = `${index + 1}张图片上传成功`;
} else {
this.message = `${index + 1}张图片上传失败`;
}
}
// 在循环外侧拿到返回的图片路径
console.log(resultImage);
},
// 上传方法,方法成功会返回一个线上的URl图片路径
uploadPostFun(data) {
return http.post("/fileupload/image", data);
},
},
};
</script>
上述代码中利用 for of 遍历配合 async await 完美的实现等待调用,返回结果在进行下一次循环
实现的效果如下,选择图片点击上传

控制台拿到返回的数据

拿到数据后就可以将这些数据给后端,其他页面请求相关接口查询地址展示图片。
