背景介绍

  1. 需求背景

2、使用 el-upload是因为:

在网上看了大家的实现方案,发现要不然就是使用 input 进行批量上传;使用 el-upload的场景都需要两个按钮【选择文件、上传】才能实现上面的诉求,考虑到这样的交互都不太友好,所以使用自己的方式实现。

一、实现效果

  1. 先来说说实现的效果,点击上传按钮,弹出文件选择,选择后直接调用上传接口进行上传,只调用一个接口。

  2. 项目效果
    功能效果

请求
Vue 批量上传,使用 el-upload 实现批量上传文件只调用一个请求,只需要一个上传按钮
template代码
Vue 批量上传,使用 el-upload 实现批量上传文件只调用一个请求,只需要一个上传按钮
request代码
Vue 批量上传,使用 el-upload 实现批量上传文件只调用一个请求,只需要一个上传按钮

二、具体说明

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的原因下面说明一下。

Vue 批量上传,使用 el-upload 实现批量上传文件只调用一个请求,只需要一个上传按钮

下面是防抖函数的逻辑说明,具体可以根据自己的应用场景去开发这里的逻辑

/**
 * @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)

三、结语

至此,个人认为比较完美的解决了问题,分享出来希望可以帮助到有同样问题的人~