zoukankan      html  css  js  c++  java
  • 前端js实现导出大量数据的excel文件

    文章原文: https://www.cnblogs.com/yalong/p/15095651.html

    前端导出excel文件,最开始使用xlsx, react 环境下代码如下所示

    import XLSX from 'xlsx';
    const exportExcel = (headers, data, fileName) => {
      const _headers = headers
        .map((item, i) =>
          Object.assign(
            {},
            {  
              key: item.key || item.dataIndex,
              title: item.title,
              position: String.fromCharCode(65 + i) + 1,
            },
          ),
        )
        .reduce(
          (prev, next) =>
            Object.assign({}, prev, {
              [next.position]: { key: next.key, v: next.title },
            }),
          {},
        );
    
      const _data = data
        .map((item, i) =>
          headers.map((key, j) =>
            Object.assign(
              {},
              {
                content: item[key.key || key.dataIndex],
                position: String.fromCharCode(65 + j) + (i + 2),
              },
            ),
          ),
        )
        // 对刚才的结果进行降维处理(二维数组变成一维数组)
        .reduce((prev, next) => prev.concat(next))
        // 转换成 worksheet 需要的结构
        .reduce(
          (prev, next) =>
            Object.assign({}, prev, {
              [next.position]: { v: next.content, t: typeof next.content === 'number' ? 'n' : undefined },
            }),
          {},
        );
    
      // 合并 headers 和 data
      const output = Object.assign({}, _headers, _data);
      // 获取所有单元格的位置
      const outputPos = Object.keys(output);
      // 计算出范围 ,["A1",..., "H2"]
      const ref = `${outputPos[0]}:${outputPos[outputPos.length - 1]}`;
    
      // 构建 workbook 对象
      // TODO: 这里固定设置了前8个col的宽度,不太适用于通用util
      const wb: WorkBook = {
        SheetNames: ['mySheet'],
        Sheets: {
          mySheet: Object.assign({}, output, {
            '!ref': ref,
            '!cols': [
              { wpx: 45 },
              { wpx: 100 },
              { wpx: 200 },
              { wpx: 80 },
              { wpx: 150 },
              { wpx: 100 },
              { wpx: 300 },
              { wpx: 300 },
            ],
          }),
        },
      };
    
      // 导出 Excel
      XLSX.writeFile(wb, fileName, {
        ignoreEC: true,
      });
    };
    

    使用方式如下:

    const initalColumns = [
      {
          title: '名字',
          dataIndex: 'name',
          key: 'name',
        },
       
          title: '年龄',
          dataIndex: 'age',
          key: 'age',
        },
     ]
     const initList = [
        {
          name: '张三',
          age: 18,
        },
        {
          name: '李四',
          age: 20,
        },
      ];
     exportExcel(initalColumns, initList, '统计表格.xlsx')
    

    上面这种方式在数据量比较少的时候,没问题, 300条以内都可以接受, 但是数据量大了以后,比如上千条数据,这时候,就很卡,有时候浏览器会崩溃
    为了解决大量数据的导出excel问题,通过查阅资料,发现可以把文件导出成csv格式的文件,这时候导出时间就降低了很多

    excel 跟csv文件格式对比如下:


    简单来说,就是

    1. csv格式的文件是文本格式,体积更小,文件解析快,可以通过记事本、office excel等打开
    2. excel格式的文件功能多,但是体积大,文件解析慢
    3. 同样的数据,excel格式体积是280KB, csv格式体积只有80KB
    4. csv格式的文件用office excel 打开 跟 excel 文件效果是一样的

    导出csv格式文件代码如下:

    const exportExcel2 = (initColumns: any, initList: any, name: string) => {
      let str: string = '';
      let arr: string[] = [];
      let keyArr: string[] = [];
      initColumns.forEach((item) => {
        arr.push(item['title']);
        keyArr.push(item['key']);
      });
      str = arr.join(',') + '
    ';
      for (let i = 0; i < initList.length; i++) {
        let subArr = keyArr.map((item) => {
          let temp = initList[i][item] === undefined ? '' : initList[i][item] + ''; // 转成字符串
          // 下面解决中文乱码问题 会把空格转成 #, 这里把空格转成 xa0 就不会有这个问题了
          return temp ? temp.replaceAll(/s+/g, 'xa0') : '';
        });
        let subStr = subArr.join('	,');
        subStr += '
    ';
        str += subStr;
      }
      // ufeff 解决中文乱码问题
      var blob = new Blob(['ufeff', str], { type: 'text/plain' });
      let object_url = window.URL.createObjectURL(blob);
      let link = document.createElement('a');
      link.href = object_url;
      link.download = `${name}.csv`;
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
    };
    

    使用方式如下:

    const initalColumns = [
      {
          title: '名字',
          dataIndex: 'name',
          key: 'name',
        },
       
          title: '年龄',
          dataIndex: 'age',
          key: 'age',
        },
     ]
     const initList = [
        {
          name: '张三',
          age: 18,
        },
        {
          name: '李四',
          age: 20,
        },
      ];
     exportExcel2(initalColumns, initList, '统计表格')
    

    经测试 1万条数据可以在3秒内下载完毕,速度还可以了。

    最后可以考虑把该函数封装成npm包,以后用的时候更方便了, 怎么把js函数封装成npm包教程看这里: https://www.cnblogs.com/yalong/p/15214644.html

  • 相关阅读:
    Day05_java方法 方法
    Day05_java流程控制 break、continue
    Day05_java流程控制 循环结构
    Day05_java流程控制 switch选择结构
    Day05_java流程控制结构
    Day04_java流程控制 顺序结构
    Day04_java流程控制 用户交换Scanner
    Day03_java基础 JavaDoc生成文档
    Day03_java基础 包机制
    ltib学习抄录
  • 原文地址:https://www.cnblogs.com/yalong/p/15095651.html
Copyright © 2011-2022 走看看