vue + Excel document element-ui + xlsx implemented distal check uploaded

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
This link: https://blog.csdn.net/red_sheeps/article/details/83240959


GitHub to see the code here .

background

Whether the project needs to be verified to upload an Excel template compliance. The idea is to verify the beginning of the back end, but then thought of a batch file to run 2M is the largest, if placed in the back-end calibration for non-standard documents, which 2M transmission will be wasted, and at the same time, for the user experience is very bad, you want to check placed on the client, not normative files directly got rejected, save bandwidth while also improved the customer experience.

Code course

Project is using vue+element-uito build web projects, then the Excel front-end to achieve resolve, we need to add xlsx.js plug.
Install plug-ins npm i xlsx --save, of course, it can also be so cnpm i xlsx --save.

Failure code

Beginning to use element-uithe code below, upload function implementation. This embodiment will check through the Excel format.
When Excel meet this format, it will check through

<el-upload
      style="display: inline; margin-left: 10px;margin-right: 10px;"
      action="#"
      ref="fileupload"
      :show-file-list="false"
      :http-request="upLoadChange"
      :before-upload="beforeUpload">
      <el-button size="small" type="primary">上传文件<i class="el-icon-upload el-icon--right"></i></el-button>
    </el-upload>

The check code in the beforeUploadprocess, as follows:

  beforeUpload(file) {
    // 读取Excel文件并校验返回Boolean值
    let readExcelResult = this.readExcel(file);
    console.log(readExcelResult);
    if (readExcelResult) {
      const isLt2M = file.size / 1024 / 1024 < 2;
      if (!isLt2M) {
        this.$message.error('文件大小不能超过2MB!');
        return false;
      }
      this.$message.success('校验成功!');
      return true;
    } else {
      this.$message.error('校验文件失败');
      return false;
    }
  }

readExcelMethod code is as follows:

readExcel(file) {// 解析Excel
        let _this = this;
        const reader = new FileReader();
        reader.onload = (e) => {
          try {
            // 以二进制流方式读取得到整份excel表格对象
            var data = e.target.result, workbook = XLSX.read(data, {type: 'binary'});
          } catch (e) {
            this.$message.error(e.message);
            return false;
          }

          // 表格的表格范围,可用于判断表头是否数量是否正确
          var fromTo = '';
          // 遍历每张表读取
          for (var sheet in workbook.Sheets) {
            let sheetInfos = workbook.Sheets[sheet];
            let locations = [];// A1,B1,C1...
            if (workbook.Sheets.hasOwnProperty(sheet)) {
              fromTo = sheetInfos['!ref'];// A1:B5
              // 该方法获取每列第一行的值,如:输入A1:B5,返回['A1','B1'],该方法详情可查看文章末尾的github具体代码
              locations = _this.getLocationsKeys(fromTo);
            }

            for (let i = 0;i < locations.length; i++) {
              let value = sheetInfos[locations[i]].v;

              if (value != i) {
                this.$message.error(locations[i] + '\'s parameter isn\'t ' + i);
                return false;
              }
            }
            return true;
          }
        };
        reader.readAsBinaryString(file);
      }

problem found

Code looks okay, but do not pass up, F12 and later tracked down and found that readExcelResulthas been undefined, so check leading to abnormal.Abnormal return

Optimized code

  1. I believe the vast majority of people have found the problem, in readExcelthe method load the relevant code is executed asynchronously, and will not be blocked, so this method will soon execute the end, the results did not return to what it led directly to the above question , readExcelResultis undefined, then began searching synchronous asynchronous transfer, Sure, the results are used promiseto achieve.
  2. To see element-uithe official documentation to see such a sentence:
    element-ui upload using the introduction of
    It seems it can only be to implement features I need.

After fine-tuning the code

The following is the beforeUploadcode changes:

  beforeUpload(file) {
    let _this = this;
    // 使返回的值变成Promise对象,如果校验不通过,则reject,校验通过,则resolve
    return new Promise(function(resolve, reject){
      // readExcel方法也使用了Promise异步转同步,此处使用then对返回值进行处理
      _this.readExcel(file).then(result => {// 此时标识校验成功,为resolve返回
        const isLt2M = file.size / 1024 / 1024 < 2;
        if (!isLt2M) {
          _this.$message.error('文件大小不能超过2MB!');
        }
        if (isLt2M && result){
          resolve('校验成功!');
        } else {
          reject(false);
        }
      }, error => {// 此时为校验失败,为reject返回
        _this.$message.error(error);
        reject(false);
      });
    });
  }

The following is the readExcelcode changes

  readExcel(file) {// 解析Excel
    let _this = this;
    return new Promise(function(resolve, reject){// 返回Promise对象
      const reader = new FileReader();
      reader.onload = (e) => {// 异步执行
        try {
          // 以二进制流方式读取得到整份excel表格对象
          var data = e.target.result, workbook = XLSX.read(data, {type: 'binary'});
        } catch (e) {
          reject(e.message);
        }

        // 表格的表格范围,可用于判断表头是否数量是否正确
        var fromTo = '';
        // 遍历每张表读取
        for (var sheet in workbook.Sheets) {
          let sheetInfos = workbook.Sheets[sheet];
          let locations = [];// A1,B1,C1...
          if (workbook.Sheets.hasOwnProperty(sheet)) {
            fromTo = sheetInfos['!ref'];// A1:B5
            locations = _this.getLocationsKeys(fromTo);
          }

          for (let i = 0;i < locations.length; i++) {
            let value = sheetInfos[locations[i]].v;
            if (value != i) {// 自定的校验规则,自由实现即可
              // 校验失败reject
              reject(locations[i] + '\'s parameter isn\'t ' + i);
            }
          }
          // 校验成功resolve
          resolve(true);
        }
      };
      reader.readAsBinaryString(file);
    });
  }

The following is getLocationsKeysthe code

getLocationsKeys(range) {// A1:B5输出 A1,B1...,如果超过26个就会出现,A1:AA1情况,以此类推,也可能出现BA1(BZ1)
        let rangeArr = range.split(':');
        let startString = rangeArr[0];
        let endString = rangeArr[1];

        var reg=/[A-Z]{1,}/g;
        let end = endString.match(reg)[0];


        let total = 0;// 共有多少个
        for (let index = 0;index < end.length;index++) {
          total += Math.pow(26, end.length - index - 1) * (end.charCodeAt(index) - 64);
        }

        let result = [];
        for (let i = 0;i < total;i++) {
          result.push(this.getCharFromIndex(i) + '1');
        }
        return result;
      },

execution succeed

The above code perfect solution to the problems encountered before, to check and correct returned
The correct implementation of the results

to sum up

  1. At this point the entire file uploaded to the file checksum whole process to make people very comfortable. Do not wait a long time before responding, if the failure was a result of the check, the user experience on the go.
  2. Use of Promisethe key, asynchronous transfer synchronization, the whole lambdasyntax to make the code easy to understand, for the first time, the feeling is particularly strong.
  3. As a person engaged in a perennial back-end, and occasionally solve think a little tricky problem of front-end feel under great sense of accomplishment, Mark.

Comments are welcome ~~~~~~

Guess you like

Origin blog.csdn.net/red_sheeps/article/details/83240959