背景介绍
- 需求背景
- 后端需要批量对上传的文件进行处理
- 原生的 el-upload 批量上传会多次调用上传接口,不支持一次调用
- 前端需要对选择的文件进行批量校验
2、使用 el-upload
是因为:
- 项目是基于饿了吗组件库开发的,不想再引入其他的组件进行开发;
- 原生的
input
实现上传样式处理也比较费劲。
在网上看了大家的实现方案,发现要不然就是使用 input 进行批量上传;使用 el-upload
的场景都需要两个按钮【选择文件、上传】才能实现上面的诉求,考虑到这样的交互都不太友好,所以使用自己的方式实现。
一、实现效果
-
先来说说实现的效果,点击上传按钮,弹出文件选择,选择后直接调用上传接口进行上传,只调用一个接口。
-
项目效果
功能效果
请求
template
代码
request
代码
二、具体说明
0. data变量说明
data() {
return {
uploadCfg: {
fileList: [], // 默认绑定的文件列表
validFileList: [] // 通过校验的文件列表
}
};
}
下面来解释下以上template
中重要的两个组件属性
1. handleBeforeUpload
上传文件之前的校验:至少要包含一个excel
文件;如果校验通过,请求接口;如果校验不通过,终止接口的请求,并给出校验不通过的提示。
/**
* @desc 上传之前进行文件校验
* @param file 当前文件
*/
handleBeforeUpload(file){
let vm = this;
return new Promise((resolve, reject) => {
// 收集文件列表
this.uploadCfg.validFileList.push(file);
// 校验文件列表
vm.handleDebounceVarifyFile();
setTimeout(function (){
if (!_.isEmpty(vm.uploadCfg.validFileList)){
resolve(true);
} else {
reject(true);
}
}, 100);
});
}
可以看到这里返回了Promise
,看下官方给的解释,如下图,就是说支持用 Promise
的方式返回结果,没有直接返回 false
的原因下面说明一下。
-
el-upload
的handleBeforeUpload
会在批量上传的时候触发多次,即选择几个文件就会调用几次,我们的需求是,至少要包含一个excel
文件,这种情况下需要收集所有选中的文件进行批量校验,单个的触发是不能满足的,所以这里使用了一个【防抖函数】handleDebounceVarifyFile
通过短时间内最后一次触发,来达到批量校验文件的效果。
因为会多次触发,所以这里的校验函数,返回的是一个Promise
。
下面是防抖函数的逻辑说明,具体可以根据自己的应用场景去开发这里的逻辑
/**
* @desc 防抖触发文件上传前,保证批量校验
*/
handleDebounceVarifyFile: _.debounce(function (){
let excel_file = {};
if (_.isEmpty(this.uploadCfg.validFileList)){
return;
}
excel_file = this.uploadCfg.validFileList.find(item => {
return /\.(xls)|\.(xlsx)$/.test(item.name);
});
// 如果文件校验不合理,清空合法文件列表,并提示
if (_.isEmpty(excel_file)){
this.uploadCfg.validFileList = [];
this.$message.warning('至少上传一个xls或者xlsx格式的文件!');
}
}, 20)
2. handleUploadHttp
这里使用自定义的上传方法,和上传前校验一样, el-ipload
默认会多次调用上传接口,我们需要做的也是使用防抖的思路,控制最后一次触发上传回调的时候去构造批量的文件数据,请求接口,下面是具体代码:
/**
* @desc 自定义上传
*/
handleUploadHttp(){
this.handleDebounceUpload();
}
/**
* @desc 防抖触发文件上传前,保证批量上传
*/
handleDebounceUpload: _.debounce(function (){
if (_.isEmpty(this.uploadCfg.validFileList)){
return;
}
let formData = new FormData();
this.uploadCfg.validFileList.forEach((item_file) =>{
formData.append(`files`,item_file);
});
batchUploadApi.uploadXsxx(formData).then(()=> {
this.$message.success('附件已上传成功,请等待数据入库!');
this.uploadCfg.validFileList = [];
}).catch(err => {
console.log('批量上传附件失败', err);
});
}, 20)
三、结语
至此,个人认为比较完美的解决了问题,分享出来希望可以帮助到有同样问题的人~