基于Vue实现Excel解析与导出功能详解

前言

最近在整理日常开发中长涉及到的业务需求,正好想到了excel的解析与上传方面的事情,在开发中还是比较常见的,趁着周末做一下整理学习吧

4322BABD-FFFD-7D66-1F5E-78AC155AF014.png

基本介绍

主要基于Vue+element实现文件的解析与导出,用的的插件是 xlsx,里面的具体方法,感兴趣的去研究一下,基本的样式,配置就不赘述了,也比较简单,我们直接上主食

代码实现
基本结构

用户点击文件上传,将excel的表格已json的格式显示在页面中,用户进行操作,检查数据后对服务进行提交,上传操作用的的element中的upload组件

<!-- 上传文件按钮 -->
   <div class="buttonBox">
     <el-upload
       action
       accept=".xlsx, .xls"
       :auto-upload="false"
       :show-file-list="false"
       :on-change="handle"
     >
       <el-button type="primary" slot="trigger">选取EXCEL文件</el-button>
     </el-upload>

     <el-button type="success" @click="submit" :disabled="disable">采集数据提交</el-button>
   </div>

   <!-- 解析出来的数据 -->
   <div class="tableBox" v-show="show">
     <h3>
       <i class="el-icon-info"></i>
       小主,以下是采集完成的数据,请您检查无误后,点击“采集数据提交”按钮上传至服务器哦!
     </h3>

     <el-table :data="tempData" style="width: 100%" :height="height" border>
       <el-table-column prop="name" label="姓名" min-width="50%"></el-table-column>
       <el-table-column prop="phone" label="电话" min-width="50%"></el-table-column>
     </el-table>
   </div>
上传解析
  • 通过upload组件可以获取上传的文件流(下图)

4D416F12-BA93-D835-7895-33CACF77D46E.png

  • 将文件流转为二进制,这里我们可以在utils文件中增加对应的方法(如下)

    // 把文件按照二进制进行读取
    export function readFile(file){
        return new Promise(resolve => {
            let reader = new FileReader();
            reader.readAsBinaryString(file);
            reader.onload = ev => {
                 resolve(ev.target.result);
            };
        });
     }
  • 通过xlsx将二进制六转为json,这样才能显示

    //读取FILE中的数据(变为JSON格式)
      let data = await readFile(file);
      let workbook = xlsx.read(data, { type: "binary" }),
        worksheet = workbook.Sheets[workbook.SheetNames[]];
      data = xlsx.utils.sheet_to_json(worksheet);
      // 打印结果加下图
      console.log(workbook);

8600547C-07C3-BBCF-EA70-551202205C68.png

  • 把读取出来的数据变为最后可以传递给服务器的数据,我们需要先封装一个映射表来对应传给后端的格式(如下)

    // 字段对应表
        export let character = {
            name: {
                text: "姓名",
                type: 'string'
            },
            phone: {
                text: "电话",
                type: 'string'
            }
        };
  • 转换数据格式

    let arr = [];
        data.forEach(item => {
            let obj = {};
            for (let key in character) {
              if (!character.hasOwnProperty(key)) break;
              let v = character[key],
                text = v.text,
                type = v.type;
              v = item[text] || "";
              type === "string" ? (v = String(v)) : null;
              type === "number" ? (v = Number(v)) : null;
              obj[key] = v;
            }
          arr.push(obj);
        });
  • 发送给服务器

这里要看服务器支持多条文件一起发送,如果不支持我们前端就可以采用递归逐条发送的方式进行发送,具体情况可以与后端进行沟通,我们这采用递归的方式进行传输

// 提交数据给服务器
    async submit() {
      if (this.tempData.length <= ) {
        this.$message({
          message: "小主,请您先选择EXCEL文件!",
          type: "warning",
          showClose: true
        });
        return;
      }

      this.disable = true;
      let loadingInstance = Loading.service({
        text: "小主,请您稍等片刻,奴家正在玩命处理中!",
        background: "rgba(0,0,0,.5)"
      });

      // 完成后处理的事情
      let complate = () => {
        this.$message({
          message: "小主,奴家已经帮您把数据上传了!",
          type: "success",
          showClose: true
        });
        this.show = false;
        this.disable = false;
        loadingInstance.close();
      };

      // 需要把数据一条条传递给服务器
      let n = ;
      let send = async () => {
        if (n > this.tempData.length - 1) {
          // 都传递完了
          complate();
          return;
        }
        let body = this.tempData[n];
        // 走接口
        let result = await createAPI(body);
        if (parseInt(result.code) === ) {
          // 成功
          n++;
        }
        send();
      };
      send();
    }

以上就是对Excel文件的解析与上传的总结,其实并不是很难,都是日常开发常常涉及的业务,接下来一起看下Excel的导出吧

Excel的导出
基本结构

一进来页面获取刚刚上传的文件,然后显示在表格中,然后做个分页.......这些就不说了,我们直接从点击导出excel按钮开始,先看下页面结构

<div class="container">
    <!-- 上传按钮 -->
    <div class="buttonBox">
      <router-link to="/upload">
        <el-tooltip content="EXCEL数据采集" placement="top">
          <el-button type="primary" icon="el-icon-edit" circle></el-button>
        </el-tooltip>
      </router-link>
    </div>

    <!-- 搜索区域 -->
    <div class="searchBox">
      <el-input v-model="search" placeholder="基于姓名、手机模糊搜索" @change="searchHandle"></el-input>
      <el-button type="success" @click="submit" :disabled="disabled">导出选中的数据</el-button>
    </div>

    <!-- 列表区域 -->
    <div class="tableBox">
      <el-table
        :data="tableData"
        :height="height"
        style="width: 100%"
        v-loading="loading"
        element-loading-text="小主,奴家正在努力加载中..."
        @selection-change="selectionChange"
      >
        <el-table-column type="selection" width="50" align="center"></el-table-column>
        <el-table-column prop="id" label="编号" min-width="10%"></el-table-column>
        <el-table-column prop="name" label="姓名" min-width="20%"></el-table-column>
        <el-table-column prop="phone" label="电话" min-width="20%"></el-table-column>
        <el-table-column prop="time" label="创建时间" min-width="25%" :formatter="formatter"></el-table-column>
      </el-table>
    </div>

    <!-- 分页区域 -->
    <div class="pageBox">
      <el-pagination
        background
        hide-on-single-page
        layout="total, sizes, prev, pager, next"
        :page-size="pageSize"
        :current-page="page"
        :total="total"
        @size-change="sizeChange"
        @current-change="prevNext"
        @prev-click="prevNext"
        @next-click="prevNext"
      ></el-pagination>
    </div>
  </div>
导出Excel

将json数据变为sheet数据,新建表格,在表格中插入一个sheet,通过xlsx的writeFile方法将文件写入

// 导出数据
    submit() {
      if (this.selectionList.length <= ) {
        this.$message({
          message: "小主,请您先选择要导出的数据哦!",
          type: "warning",
          showClose: true
        });
        return;
      }

      this.disabled = true;
      let loadingInstance = Loading.service({
        text: "小主,请您稍等片刻,奴家正在玩命处理中...",
        background: "rgba(0,0,0,.5)"
      });

      let arr = this.selectionList.map(item => {
        return {
          编号: item.id,
          姓名: item.name,
          电话: item.phone
        };
      });
      // 将json数据变为sheet数据
      let sheet = xslx.utils.json_to_sheet(arr),
      // 新建表格
        book = xslx.utils.book_new();
      // 在表格中插入一个sheet
      xslx.utils.book_append_sheet(book, sheet, "sheet1");
      // 通过xlsx的writeFile方法将文件写入
      xslx.writeFile(book, `user${new Date().getTime()}.xls`);

      loadingInstance.close();
      this.disabled = false;
    }
收藏 (0)
评论列表
正在载入评论列表...
我是有底线的
为您推荐
    暂时没有数据