前端导出Excel实践指北

程序员成长指北

共 6170字,需浏览 13分钟

 ·

2021-07-09 14:36


点击上方 程序员成长指北,关注公众号

回复1,加入高级Node交流群

Hello, 各位勇敢的小伙伴, 大家好, 我是你们的嘴强王者小五, 身体健康, 脑子没病.

本人有丰富的脱发技巧, 能让你一跃成为资深大咖.

一看就会一写就废是本人的主旨, 菜到抠脚是本人的特点, 卑微中透着一丝丝刚强, 傻人有傻福是对我最大的安慰.

欢迎来到小五随笔系列前端导出Excel在线指北.

写在前面

双手奉上代码链接 传送门 - ajun568

双脚奉上最终效果图

观前提醒

👺 本文最终实现效果如上图, 具体功能为: 导出Excel + 多个Sheet + 可合并的多行表头. 代码部分采用 React+TS 作为工具进行编写.

准备工作

👺 安装 xlsx.js npm install xlsx

👺 写入Excel文件: XLSX.write(workbook, writeOpts)

workbook 👇

  • SheetNames @types string[]: 当前 Sheet 的名称
  • Sheets: 当前sheet的对象, 格式如下
[SheetNames]: {
  "!refs""A1:G7"// 表示从 第1行第A列 到 第7行第G列
  "!cols": [{wpx80} ... ], // 表示 列宽 80px
  "!rows": [{hpx20} ... ], // 表示 行高 20px
  "!merges": [{s: {r0c2}, e: {r0c3}} ... ], // 表示 将 第0行第2列 和 第0行第3列 进行合并 (s: start, e: end, c: column, r: row)
  "A1": {v"姓名"}, // 表示第1行第A列 显示数据为 "姓名", 以此类推 ...
  ...
}

writeOpts 👇

{
  type, // 数据编码, 本文采用 binary 二进制格式
  bookType, // 导出类型, 本文采用 xlsx 类型
  compression, // 是否使用 Gzip 压缩
}

下载文件

想要下载文件, 我小A第一个表示不服, 申请出战 <a 标签的 download 属性>

通过 URL.createObjectURL(Object) 来创建下载所需的 URL. 由于每次调用都会产生新的 URL 对象, 故使用后记得释放, 释放方法 URL.revokeObjectURL(FileUrl)

通过模拟 click 事件触发 a 标签, 以实现下载

const saveAs = (obj: Blob, fileName?: string): void => {
  const temp = document.createElement('a')
  temp.download = fileName || 'download'
  temp.href = URL.createObjectURL(obj)
  temp.click()
  setTimeout(() =>  { URL.revokeObjectURL(temp.href) }, 100)
}

头部处理

Mock数据: 详细数据请跳转 Github, 在 mock.ts 中查看

Header 部分数据格式

[
  ...
  {
    key'animal',
    value'动物',
    child: [
      {
        key'dog',
        value'狗',
        child: [
          {
            key'corgi',
            value'柯基',
          },
          {
            key'husky',
            value'哈士奇',
          },
        ],
      },
      {
        key'tiger',
        value'老虎',
      },
    ],
  },
  ...
]

Data 部分数据格式

[
  {
    name'黄刀小五',
    desc'基于搜索引擎的复制粘贴攻城狮',
    watermelon'喜欢',
    banana'不喜欢',
    corgi'喜欢',
    husky'喜欢',
    tiger'不喜欢',
  },
  ...
]

头部数据处理

👺 分析

  • Header 数据为树形结构, 其深度为头部所占行数
  • Header 数据要转换成 Data 数据的格式, 并与 Data 数组合并, 共同处理成导出所需格式
  • 转换对象的 key 应为最小叶子结点的 key
  • 转换对象的 value 应为当前层级的 value ( 即导出后当前行所显示的 value )
  • 既然是树, 果断递归, 准没错

🧟‍♂️ Code

excel2.png

🧟‍♂️ Image

Merged 数据

{
  s: { // start
    r: x, // row
    c: y, // column
  },
  e: { ... } // end
}

👺 分析

  • 将处理后的头部数据看成一个矩阵
  • 行或列中, 相邻元素若相同, 则进行合并

tips: 本文采用的是判断相邻 value 值是否相等进行合并, 若有需求, 建议改写为对象形式加以完善.

🧟‍♂️ Code

excel4.png

🧟‍♂️ Image

生成sheet数据

  • 利用Object.assign进行对象合并
  • 利用String.fromCharCode(65 + i)对列进行大写字母的转换

🧟‍♂️ Code

excel13.png

🧟‍♂️ Image

转换字节流

利用 new ArrayBuffer(str) 创建一个缓冲区, 使用 new Uint8Array(buf) 引用

因为 unicode 编码是 0~65535, 而 Uint8Array 范围为 0~255, 故需要按位与 0xFF, 以保持位数一致

const s2ab = (str: string): ArrayBuffer => {
  let buf = new ArrayBuffer(str.length)
  let view = new Uint8Array(buf)

  for (let i = 0; i !== str.length; ++i) {
    view[i] = str.charCodeAt(i) & 0xFF
  }

  return buf
}

导出文件

结合前文 准备工作 部分所讲, 导出的代码逻辑就出来了, 直接上代码

excel14.png

结束语

开源版本不支持设置样式, 若有需求, 可采用 付费版本 或使用 xlsx-style, 使用方法与本文一致. 大家可参照文档自行添加样式部分.

参考🔗链接

【Github】 SheetJS ~ js-xlsx

【mySoul】 优雅 | 前后端优雅的导入导出Excel

【Seefly】 前端使用xlsx.js导出有复杂表头的excel

关于本文
来源:黄刀小五
https://segmentfault.com/a/1190000040067999
如果觉得这篇文章还不错
点击下面卡片关注我
来个【分享、点赞、在看】三连支持一下吧

   “分享、点赞在看” 支持一波 

浏览 28
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报