项目场景:
利用elementUI的一个后台管理项目, 需要实现批量上传的功能, 正好el-upload有对应的属性multiple
属性:
multiple
描述:是否支持多选文件
类型:boolean
el-upload
默认是单个文件上传, 一般都是拿到文件然后自定义自己的上传方法(OSS, MinIO…)
问题描述:
当采用多选文件之后会发现, 上传的进度条会反复横跳(上传进度一直在变化…), 上传的文件越多, 横跳的速度, 频率就越快, 就很离谱😨
原因分析:
打开多选文件之后, 弹起选择文件的弹窗之后可以选择多个文件, 我一开始想的是先拿到所有的文件列表或者文件数组, 然后处理上传参数接着进行上传, 但是事实并不是这样的.😭
el-upload
会拿到所有的文件列表, 然后直接全部上传, 如果没有进度条的话很正常, 所有的文件都在上传, 上传成功即可, 但是如果有进度条的话就会出现横跳的问题, 因为进度条只有一个如图:
但是很多个文件都在上传, 那么每个文件上传都会把自己的进度返回, 就导致进度条被抢占, 就出现了横跳的问题.
解决方案:
其实这个解决也不难, 最简单粗暴的就是去掉进度条, 但是这个方法不太可行, 其实最关键的问题就是多个文件在同时上传, 才导致这种问题, 所以, 我们从这里入手, 如果每次只有一个文件在上传, 那么就不会出现进度条抢占的问题😊
在一顿思考过后, 采用了上传队列的方法, 具体来说就是, 首先将文件列表放到一个队列里, 然后上传第一个, 上传成功或者失败之后, 再去上传下一个, 进而全部上传, 封装一个简单队列代码如下:
class UploadTaskClient {
constructor(func) {
this._taskList = [];
this._doing = false;
this._func = func;
}
addTasks(tasks) {
this._taskList.push(...tasks);
if (!this._doing) {
this._doing = true;
this._doTask();
}
}
_doTask() {
const curTask = this._taskList.shift();
if (!curTask) return this._doing = false;
this._func(curTask, () => {
this._doTask();
});
}
}
module.exports = UploadTaskClient;
以及上传组件的核心代码
// this.uploadNextFileFunc 调取下一个文件的上传事件
setUploader() { // mounted时候执行, 初始化队列
this.UploadTaskClient = new UploadTaskClient((file, callback) => {
this.uploadNextFileFunc = callback;
this.reqUploadParam(file);
});
},
// ...
reqUploadParam(file) {
let params = {
key: this.prefix,
};
// 获取上传参数
getUploadParam(params)
.then((data) => {
// 上传
this.uploadResource(file, data);
})
.catch((err) => {
// 如果上传失败, 上传下一个文件
this.uploadNextFile();
});
},
// 上传下一个文件
uploadNextFile() {
this.uploadNextFileFunc && this.uploadNextFileFunc();
},
// el-upload的 :http-request方法
uploadFile({ file }) {
// 将所有的文件传入队列
this.UploadTaskClient.addTasks([file]);
}
OK, 完美解决啦🎉, 以后如果遇到需要用队列解决的问题, 都可以用上面封装的那个哦~
欢迎大家一起讨论学习😊~