摘要: 在element官网我们能发现,开启multiple为true的时候可以通过ctrl单机选中进行文件批量上传,看似好像已经万无一失了,但是多试几次就会发现,有时候会出现并发的情况,导致文件中可能有一些被重复覆盖了导致错乱,这是万万不行的。究其原因我们会发现他是每增加一个文件就会去请求一次接口,那么我们能不能把这些文件打包成一个请求去发送呢?
一:技术实现
想要去实现我们的需求首先得定义一个手动上传的方法,其次需要把auto-upload这个属性赋值为false,但是这里我们会发现一个问题,就是beforeUpload这个方法好像不执行了。对所以我们用 on-change这个钩子函数代替。它能监听到每一次选中文件的变化。
<template>
<el-upload
:action="base + action"
:show-file-list="false"
:on-remove="removeFile"
:multiple="true"
:file-list="fileList"
:on-change="handleChange"
:auto-upload="false"
:limit="10"
:on-exceed="handleExceed"
accept=".jpg, .jpeg, .png, .jfif, .svg, .webp, .gif, .bmp"
>
<el-button slot="trigger" type="primary">选取文件</el-button>
<el-button @click="uploadFile" type="primary">导入</el-button>
</el-upload>
</template>
// 选择文件时,往fileList里添加
handleChange(files, fileList) {
this.fileList.push(files)
},
// 移除文件
removeFile(file) {
// 移除文件时,要重新给fileList赋值
const arr = []
for (let i = 0; i < this.fileList.length; i++) {
if (this.fileList[i].uid !== file.uid) {
arr.push(this.fileList[i])
}
}
this.fileList = arr
},
手动上传的关键是将二进制文件和文件名打包成一个数组发送过去
// 手动文件上传
uploadFile() {
if (this.fileList.length === 0) {
this.$message.warning("请选取文件")
return
}
const formData = new FormData()
// 因为要传一个文件数组过去,所以要循环append
this.uploadData.factureNo = this.factureNo
this.fileList.forEach((file, index) => {
formData.append("file", file.raw)
this.uploadData.fileName.push(file.raw.name)
})
formData.append("factureNo", this.factureNo)
formData.append("fileName", this.uploadData.fileName)
// orderMoreUploadImage是我自己定义的接口
orderMoreUploadImage(formData).then((res) => {
if (res.code === 0) {
// 上传成功的操作
this.$emit("returnData", res.data) // 根据自己的业务需要来执行对应的操作
} else {
this.$message.error(res.msg)
}
this.fileList = []
})
},
为这种格式的时候证明就已经成功了
但到这里还没完,我们现在是先选取文件再去上传服务器。那么有没有办法一次到位呢?在选取文件文件确定后就去发送请求到服务器而不需要用户进行多余的点击。
<el-upload
:action="base + action"
:show-file-list="false"
:on-remove="removeFile"
:multiple="true"
:file-list="fileList"
:on-change="handleChange"
:auto-upload="false"
:limit="10"
:on-exceed="handleExceed"
accept=".jpg, .jpeg, .png, .jfif, .svg, .webp, .gif, .bmp"
>
<el-button slot="trigger" type="primary">导入</el-button>
</el-upload>
二:持续优化
找遍了整个官方文档好像都没有找到合适的钩子函数,但是我们在前面有提到on-change这个钩子函数,在选取文件确定后就会执行方法,如果我们把uploadFile()这个函数放到这里面去执行,啊万万没想到的是居然选取了几次文件就执行几次函数,这不又回到解放前了= — =。但是别急,只要思想不滑坡,方法总比困难多。你说我们有没有可能当它为最终列表的时候再去触发这个函数。
handleChange(files, fileList) {
this.fileList.push(files)
// [解决on-change多次触发问题]
let length = fileList.length
this.maxLength = Math.max(length, this.maxLength)
setTimeout(() => {
if (length !== this.maxLength) {
return
} else {
this.uploadFile()
this.maxLength = 0
}
}, 10)
},
完美实现。在dom全部执行后,依次比较是否达到了最终值,只有为最终值的时候再去执行手动上传函数。此时已满头大汗了,(_ _)。゜zzZ