在浏览器端上传文件时,为了防止恶意用户滥用上传功能,浏览器做了很多限制。
在使用element-plus时发现,虽然一次性选中了很多的文件,但是在接口调用时,仍然是按照单文件一个一个的上传的。以下将介绍如何突破这个限制,只调用一次接口就能上传所有的文件。
我这里的思想是借助Upload组件帮我们选中文件,然后文件上传的http请求我自己去实现,通过不断的实验发现可以使用Upload 的props:on-change、http-request来实现。具体流程如下
- 当我们选择了文件之后,会调用on-change函数,此函数的第一个参数UploadFile就是我们选中的文件对象,多个文件会多次调用on-change函数,基于此我使用了fileList:Array<UploadFile>来存储上传文件,并且在存储之后直接调用Upload上的方法handleRemove,直接将其从upload组件上删除,这样我们就将待上传的文件存储到fileList。
- 由于我们设置了upload组件的自动上传,所以在调用on-change函数之后会再调用http-request函数,这里我们自定义http请求,把请求拦截下来不交给upload组件执行上传操作,由于多个文件会多次调用http-request函数,所以我们在第一次调用之后就应该把fileList清空,并在调用自定义http请求之前判断fileList是否为空。
一、效果图
二、后端代码
三、html
<el-upload
:show-file-list="false"
:multiple="true"
:limit="20"
:auto-upload="true"
:on-change="filechange"
:http-request="customRequest"
ref="uploadRef"
>
<el-button icon="Upload" plain type="info">导入</el-button>
</el-upload>
四、ts代码
//存放选中的文件
const fileList = ref<Array<UploadFile>>([])
//upload组件
const uploadRef = ref<any>(null)
//监听upload组件在文件状态变化时的钩子函数
//主要是将监听到的文件存入fileList (去重了)
function filechange(uploadFile: UploadFile, uploadFiles: UploadFiles) {
if (fileList.value.length == 0) {
fileList.value.push(uploadFile)
}
let contain = false
for (const key in fileList.value) {
const element = fileList.value[key]
if (element.name === uploadFile.name && element.size === uploadFile.size) {
contain = true
}
}
if (!contain) {
fileList.value.push(uploadFile)
}
//删除upload组件上文件的缓存
uploadRef.value.handleRemove(uploadFile, uploadFiles)
}
//自定义的上传请求
function customRequest(options: UploadRequestOptions) {
console.log('customRequest', options)
if (fileList.value.length > 0) {
//http 请求
submit()
//每次上传之后将文件清空,多个文件上传时,upload组件会多次调用customRequest方法,如果不清空会导致文件多次上传
fileList.value = []
}
}
//上传,uploadFiles是用axios实现的文件上传,函数定义往下看
function submit() {
//fileList是UploadFile数组,真正上传时不需要他,而是uploadFile.raw
const files = fileList.value.map((uploadFile) => uploadFile.raw)
uploadFiles(files)
}
五、axios
import axios, { type AxiosInstance } from 'axios'
export function uploadFiles(option: Array<File>) {
console.log('set', option)
//浏览器对于文件上传默认会将文件拆分,分多次http请求服务器,
//如果想要一次上传所有的文件,需要借助FormData对象,
//同时此对象可以添加其他的参数,
const formData = new FormData()
option.forEach((file) => {
console.log(file)
formData.append('excelFile', file)
})
return upload({
baseURL:'http://localhost',
url: '/sys/sys_user/upload',
formData
})
}
//axios请求
function upload(option: any) {
return axios.post(option.url, option.formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
baseURL:option.baseURL
})
}