有趣且重要的JS知识合集(7)前端实现表格导出excel

1、情景描述

后端提供了数据,但是不提供导出excel的接口,那怎么办?前端也可以实现excel导出噢~

2、所需依赖及示例讲解

import * as XLSX2 from 'xlsx';
import XLSX from 'xlsx-style';

注:只需要以上俩依赖,但是需要打上补丁噢~因为这俩依赖源码有点bug,至少在我现在用的时候有bug,如果你运行后无问题,那就不需要打补丁噢

补丁:

1、/node_modules/xlsx-style/dist/cpexcel.js
错误源码:var cpt = require('./cpt' + 'able');
应修改为:var cpt = cptable;
 
2、/node_modules/xlsx-style/dist/ods.js
错误源码:return require('../' + 'xlsx').utils;
应修改为:return require('./' + 'xlsx').utils;

不知道如何打补丁的童鞋请参考我另一篇博客:

【patch-package】修改node_modules下的依赖包源码 

示例:

下面变量名不懂的可以结合参考我的源码理解噢~

// props.headerDisplay: 导出excel头部
{
  autoIndex: '序号',
  originName: '视频文件',
}

// headProp: 导出excel头部属性名数组
['autoIndex', 'originName']
 
// exportData: 导出文件数据(入参)
[
    {
        autoIndex: 1,
        originName: 'xxx'
    },
    {
        autoIndex: 2,
        originName: 'xxx'
    }
]

// header (入参)
[
    {
        prop: 'autoIndex',
        width: 150
    },
    {
        prop: 'originName',
        width: 150
    }
]

结果截图:

3、源码 

 exportTransfer为导出excel的方法,俩参数我写在上面的示例里了,其余的代码基本上不用改,我都写了相关注释,你也可以根据你自己的需求进行相关更改

exportTransfer(exportData, header) {
      nextTick(() => {
        const newData = [props.headerDisplay, ...exportData] // 封装组合后的数据
        const headProp = header.map(item => item.prop) // 头部属性数组
        // 把json转为worksheet对象 后续用这种方法
        const wb = XLSX2.utils.json_to_sheet(newData, { header: headProp, skipHeader: true })
        // return
        const widthList = header.map(item => item.width ? Number(item.width) : 150)
        // 举例一共有14列(包括序号,不包括操作栏)
        wb['!cols'] = [] // 先初始化列数组配置
        for (let i = 0; i < 14; i++) {
          wb['!cols'][i] = {
            wpx: widthList[i]
          }
        }
        // 样式的文档地址
        // https://www.npmjs.com/package/xlsx-style
        for (const key in wb) {
          if (key.indexOf('!') === -1) { // 非excel配置类,带!都是配置类,这里对非配置类进行样式修改
            wb[key].s = {
              font: { // 字体设置
                sz: 13,
                bold: false,
                color: { // 只有DEFG第一行(标题行)才是红色,其余皆是黑色
                  rgb: new RegExp(/^[DEFG]1{1}$/).test(key) ? 'D9001B' : '000000'
                }
              },
              alignment: { // 文字居中
                horizontal: 'center',
                vertical: 'center',
                wrapText: 1 // 换行
              },
              border: { // 设置边框
                top: { style: 'thin' },
                bottom: { style: 'thin' },
                left: { style: 'thin' },
                right: { style: 'thin' }
              }
            }
          }
        }
        const filedata = sheet2blob(wb)
        openDownloadDialog(filedata, `xxx`)
      })
    },
    /**
     * 将一个sheet转成最终的excel文件的blob对象,然后利用URL.createObjectURL下载
     * @param sheet excel对象
     * @param sheetName
     * @returns
     */
    sheet2blob(sheet, sheetName?: string) {
      const s2ab = (s) => {
        const buf = new ArrayBuffer(s.length);
        const view = new Uint8Array(buf);
        for (let i = 0; i !== s.length; ++i) {
          view[i] = s.charCodeAt(i) & 0xFF;
        }
        return buf;
      }
      sheetName = sheetName || 'sheet1';
      const workbook = {
        SheetNames: [sheetName],
        Sheets: {}
      };
      workbook.Sheets[sheetName] = sheet; // 生成excel的配置项
      const wopts = {
        bookType: 'xlsx', // 要生成的文件类型
        bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
        type: 'binary'
      };
      const wbout = XLSX.write(workbook, wopts);
      const blob = new Blob([s2ab(wbout)], { // 字符串转ArrayBuffer
        type: 'application/octet-stream'
      });
      return blob;
    },
    /**
     * 创建excel地址并下载到本地
     * @param url 文件blob二进制路径
     * @param saveName 文件名
     */
    openDownloadDialog(url, saveName) {
      if (typeof url === 'object' && url instanceof Blob) {
        url = URL.createObjectURL(url); // 创建blob地址
      }
      const aLink = document.createElement('a');
      aLink.href = url;
      aLink.download = `${saveName}.xlsx`; // HTML5新增的属性,指定保存文件名
      let event;
      if (window.MouseEvent) {
        event = new MouseEvent('click');
      } else {
        event = document.createEvent('MouseEvents'); // 事件抛出
        event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
      }
      aLink.dispatchEvent(event); // 事件派发
    }

---本篇还是相当实用,喜欢就一键三连吧~欢迎评论---

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值