记录--前端如何优雅导出多表头xlsx

这篇具有很好参考价值的文章主要介绍了记录--前端如何优雅导出多表头xlsx。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

记录--前端如何优雅导出多表头xlsx

前言

xlsx导出是比较前后端开发过程中都比较常见的一个功能。但传统的二维表格可能很难能满足我们对业务的需求,因为当数据的维度和层次比较多时,二维表格很难以清晰和压缩的方式展现所有的信息,所以我们也就经常能碰到多级表头开发了。

demo

每当我们新使用一个插件的时候,我们都可以看着官方文档去新建立一个demo,然后去尝试一下效果,这有助于我们分析错误。

npm i xlsx -S
function exportFile() {
  const ws = utils.json_to_sheet([])
  const wb = utils.book_new()
  utils.sheet_add_aoa(ws, [
    [1, 2, 3, 4, 5, 6, 7, 8, 9], 
    ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
  ], { origin: 'A1' })
  utils.book_append_sheet(wb, ws, 'Data')
  writeFileXLSX(wb, 'SheetJSVueAoO.xlsx')
}
exportFile()

记录--前端如何优雅导出多表头xlsx

demo已经成功了,xlsx已经下载下来了。

需求分析

  1. 新建一个表格
  2. 根据表头将表格进行合并
  3. 对合并后的表头进行内容填充
  4. 填入数据内容

记录--前端如何优雅导出多表头xlsx

效果如上图(时间原因就先不写xlsx的样式了)。

需求实现

  1. 合并单元格: 需要指定开始的行和列以及结束的行和列,如{ 's': { 'r': 0, 'c': 0 }, 'e': { 'r': 3, 'c': 0 } },计算好需要合并的单元格后统一赋值给!merges属性。
  2. 合并单元格后填充内容:由多个合并后的单元格填入内容时,应该也按照多个单元格填入,只是第一个有内容,其他按空填入即可。
  3. 表头结束后我们可以指定在某一行继续填入内容,即可继续填入数据内容。
function exportFile() {
  const ws = utils.json_to_sheet([])
  ws['!merges'] = [
    { 's': { 'r': 0, 'c': 0 }, 'e': { 'r': 3, 'c': 0 } },
    { 's': { 'r': 0, 'c': 1 }, 'e': { 'r': 3, 'c': 1 } },
    { 's': { 'r': 0, 'c': 2 }, 'e': { 'r': 3, 'c': 2 } },
    { 's': { 'r': 0, 'c': 3 }, 'e': { 'r': 0, 'c': 8 } },
    { 's': { 'r': 1, 'c': 3 }, 'e': { 'r': 3, 'c': 3 } },
    { 's': { 'r': 1, 'c': 4 }, 'e': { 'r': 1, 'c': 7 } },
    { 's': { 'r': 2, 'c': 4 }, 'e': { 'r': 3, 'c': 4 } },
    { 's': { 'r': 2, 'c': 5 }, 'e': { 'r': 3, 'c': 5 } },
    { 's': { 'r': 2, 'c': 6 }, 'e': { 'r': 2, 'c': 7 } },
    { 's': { 'r': 1, 'c': 8 }, 'e': { 'r': 3, 'c': 8 } },
    { 's': { 'r': 0, 'c': 9 }, 'e': { 'r': 3, 'c': 9 } }
  ] // 合并单元格内容
  const wb = utils.book_new()
  utils.book_append_sheet(wb, ws, 'Data')
  utils.sheet_add_aoa(ws, [
    ['序号', '姓名', '性别', '公司概况', '', '', '', '', '', '备注'],
    ['', '', '', '职位', '项目', '', '', '', '公司名称'],
    ['', '', '', '', '项目时长', '项目描述', '金额', ''],
    ['', '', '', '', '', '', '总金额', '利润']
  ], { origin: 'A1' }) // 表头内容
  utils.sheet_add_aoa(ws, [
    [0, '张三', '男', '区域经理', '3天', '暂无描述', 998, 9.98, '阿里巴巴', '暂无'],
    [1, '李四', '女', 'CEO', '30天', '稳了', 998, 9.98, '中石油', '暂无']
  ], { origin: 'A5' }) // 数据内容
  writeFileXLSX(wb, `${+new Date()}.xlsx`)
}
好的,大功告成,今天就先到这里?

记录--前端如何优雅导出多表头xlsx

这东西也太丑了吧,我是一个开发,我不是来这里数格子的。看看上面的代码,我都不好意思说是我自己写的。要不到同事电脑上提交一下吧?

数据分析

[
    { 's': { 'r': 0, 'c': 0 }, 'e': { 'r': 3, 'c': 0 } },
    { 's': { 'r': 0, 'c': 1 }, 'e': { 'r': 3, 'c': 1 } },
    { 's': { 'r': 0, 'c': 2 }, 'e': { 'r': 3, 'c': 2 } },
    { 's': { 'r': 0, 'c': 3 }, 'e': { 'r': 0, 'c': 8 } },
    { 's': { 'r': 1, 'c': 3 }, 'e': { 'r': 3, 'c': 3 } },
    { 's': { 'r': 1, 'c': 4 }, 'e': { 'r': 1, 'c': 7 } },
    { 's': { 'r': 2, 'c': 4 }, 'e': { 'r': 3, 'c': 4 } },
    { 's': { 'r': 2, 'c': 5 }, 'e': { 'r': 3, 'c': 5 } },
    { 's': { 'r': 2, 'c': 6 }, 'e': { 'r': 2, 'c': 7 } },
    { 's': { 'r': 1, 'c': 8 }, 'e': { 'r': 3, 'c': 8 } },
    { 's': { 'r': 0, 'c': 9 }, 'e': { 'r': 3, 'c': 9 } }
]

记录--前端如何优雅导出多表头xlsx

我想要转成上面的数据结构,r从0开始,最大值就是它的深度,c从0开始,最大值就是它的广度。因为这是一个多级表头,每一级都会出现比上一级相等或更多子级的情况,我好像已经把答案说到嘴边了。对,就是用树形结构将其转换处理。

我们结合上面已转换好的列表结构和下面准备转换的树形结构,比如现在要合并第一个单元格序号,我们应该先找到起始位置,也就是0,0,这个很好确定;我们单单从当前节点并不能判断真正的结束位置,我们应该找到同级节点的最大深度,也就是公司概况->项目->金额->总金额,深度为3。所以它的结束位置应该为3,0

当我们要合并横向单元格的时候,比如公司概况,它下边有三个子节点分别是职位,项目,公司名称,而子节点下方仍有不同的子节点,此时我们就应该去获取它们的每个子节点的每层子节点的总长度 - 1,为什么要 - 1,因为当前节点和第一个子节点占用的是同一个col,因此可以需要减一。也就是说,如果公司概况的起始点为0,3,那么它的终止位置由此可推:职位+项目+公司名称-1+项目时长+项目描述+金额-1+总金额+利润-1 = 5。所以终点位置为0,3+5 => 0,8

const mergedCells = [ 
    { name: '序号', prop: 'id' },
    { name: '姓名', prop: 'name' },
    { name: '性别', prop: 'sex' },
    { 
        name: '公司概况', 
        children: [ 
            { name: '职位', prop: 'jobTitle' },
            { 
                name: '项目', children: [
                    { name: '项目时长', prop: 'projectTime' },
                    { name: '项目描述', prop: 'projectDesc' },
                    { 
                        name: '金额', 
                        children: [
                            { name: '总金额', prop: 'total' },
                            { name: '利润', prop: 'profit' }
                        ] 
                    } 
                ] 
            }, 
            { name: '公司名称', prop: 'companyName' }
        ] 
    },
    { name: '备注', prop: 'remark' } 
]

思路分析

  1. 找到当前节点的深度和广度
  2. 根据当前节点深度和广度,生成当前节点单元格开始与结束位置
  3. 根据当前节点深度和广度,生成表头数据结构
  4. 根据最大深度位置,生成表单列表数据

代码实现

tips: 如果你对树结构的遍历还不太熟悉,可以看看【前端不求人】树形结构和一维数组,一笑泯恩仇

获取当前节点最大广度和最大深度

  1. 递归发现当前已无子节点时,就返回0,然后每返回一层就递增1,每次返回时都获取当前节点的最大值,这样就能获得最深层数。
  2. 递归记录每层每个子节点的长度 - 1,这样就能获取当前列表的最大宽度。
  3. 我们使用map做记录,下次获取就不需要重新计算了。
const map = new Map()
const getCellsSize = list => {
    if (map.has(list)) { return map.get(list) }
    if (list?.length) {
        let rows = -1, cols = list.length - 1
        list.forEach(item => {
            if (item.children) {
                const size = getCellsSize(item.children)
                rows = Math.max(size[0], rows)
                cols += size[1]
            }
        })
        map.set(list, [rows + 1, cols])
        return [rows + 1, cols]
    }
}

合并单元格开始和结束位置

  1. 获取当前节点的开始和结束位置
  2. 当前节点无子节点,单元格宽为1,高为整个根节点的最大深度
  3. 当前节点有子节点,单元格高为1,宽为当前节点的宽,即最大广度
const size = getCellsSize(headers)
const headerMerge = []
const mergeHeadersCell = (headers, row, col) => {
    for (let i = 0, len = headers.length;i < len;i++) {
        const cell = headers[i]
        if (!cell.children?.length) {
            if (row === size[0]) { continue }
            headerMerge.push({ s: { r: row, c: col + i }, e: { r: size[0], c: col + i } })
        } else {
            const size = map.get(cell.children)
            headerMerge.push({ s: { r: row, c: col + i }, e: { r: row, c: col + size[1] + i }})
            mergeHeadersCell(cell.children, row + 1, col + i)
            col += size[1]
        }
    }
}

多表头值填充

  1. 我们声明一个headerValue的空数组来记录表头内容
  2. headerValue应该是一个二维数组,headerValue[i][j]代表第i行第j列的内容
  3. 当发现当前节点有children,直接获取当前节点的宽度,该宽度就是合并后空白单元格的个数。
  4. 当发现当前节点并没有headerValue,表示前面的节点被纵向合并了,因此应该直接加上这些空白单元格的节点
  const headerValue = []
  const getHeadersValue = (headers, row, col) => {
    if (!headerValue[row]) {
      headerValue[row] = new Array(col).fill('')
    }
    for (let i = 0, len = headers.length; i < len; i++) {
      const cell = headers[i]
      headerValue[row].push(cell.name)
      if (cell.children?.length) {
        const len = getCellsSize(cell.children)[1]
        const emptyNameList = new Array(len).fill('')
        headerValue[row].push(...emptyNameList)
        getHeadersValue(cell.children, row + 1, col + i)
      }
    }
  }

获取列表prop

  1. 继续递归mergedCells
  2. 收集无叶子节点的prop值
  3. 将prop值依次放进一个数组中以备后续使用
const bodyMapList = []
const getBodyMapList = list => {
    if (list?.length) {
        list.forEach(item => {
            !item.children ? bodyMapList.push(item.prop) : getBodyMapList(item.children)
        })
    }
}

list.map(item => bodyMapList.map(key => item[key]))

以上就是核心代码展示啦,如果想看完整代码,可以到github观看,欢迎star。

总结

我们通过计算当前树节点的大小,就可以获取该节点的广度和深度,通过广度和深度又可以让我们进一步去演算当前节点是否需要去合并其他单元格,是否需要生成空白单元格的数据内容。生成表格内容则只需要将最子层节点的prop收集,然后对应取值即可。

本文转载于:

https://juejin.cn/post/7243435843145678907

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 记录--前端如何优雅导出多表头xlsx文章来源地址https://www.toymoban.com/news/detail-485332.html

到了这里,关于记录--前端如何优雅导出多表头xlsx的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • vue3前端excel导出;组件表格,自定义表格导出;Vue3 + xlsx + xlsx-style

    当画面有自定义的表格或者样式过于复杂的表格时,导出功能可以由前端实现 1. 使用的插件 : sheet.js-xlsx 文档地址:https://docs.sheetjs.com/ 中文地址:https://geekdaxue.co/read/SheetJS-docs-zh/README.md xlsx-style:https://www.npmjs.com/package/xlsx-style 2. 安装引用 安装插件-vue3 引用插件 3. 组件表格

    2024年04月26日
    浏览(39)
  • 前端导出表格 修改样式(xlsx-style)用法

            xlsx-style 修改样式的机制  就是选中哪一行,那一列或者哪一个  然后去修改  比如表格最左上角的一个格子 坐标是 (0, 0) 下标  也可以叫做  A1 选中之后   可以修改其样式  1. 下载依赖   首先下载依赖到项目 2. 引入到项目 3. 创建导出表格         为什么

    2024年02月13日
    浏览(51)
  • 前端结合xlsx.js+xlsx-style.js源码实现自定义excel文件导出

          js-xlsx是一款非常方便的只需要纯JS即可读取和导出excel的工具库,功能强大,支持格式众多,支持xls、xlsx、ods(一种OpenOffice专有表格文件格式)等十几种格式。本文全部都是以xlsx格式为例。 创建一个excel会经历以下过程: 创建一个工作薄 创建一个sheet 创建表格行列等

    2024年03月10日
    浏览(73)
  • vue+xlsx实现前端模版下载、导入和导出excel文件

    产品需求:后端不想写下载,导入和导出的接口,让我们前端自己实现。 这里我们就可以用xlsx插件来实现,我们不多说了,先放一下实现的图片,下面我们分别把模版下载、导入和导出的代码放上来,想用的话,直接复制粘贴即可! 模版下载图片 导出图片: 好了,下面我

    2024年02月13日
    浏览(61)
  • 前端常用的上传下载文件的几种方式,直接上传、下载文件,读取.xlsx文件数据,导出.xlsx数据

    1.1根据文件流Blob进行下载 1.2根据下载文件链接直接进行下载 html

    2024年02月12日
    浏览(46)
  • 前端vue+elementui导出复杂(单元格合并,多级表头)表格el-table转为excel导出

    需求 :前端对el-table表格导出 插件 : npm install xlsx -S npm install file-saver --save 原理 :直接导出el-table的表格里面的数据,这样就会存在缺点,只会导出当前页面的数据,如果需要导出全部数据,可以自己重新渲染一个全部数据不可见的el-table表格,来导出就可以了 扩展 :经过

    2024年02月04日
    浏览(66)
  • 前端使用xlsx-js-style导出Excel文件并修饰单元格样式

    安装 导出 excel 较常见的 js 库是之一是 xlsx, xlsx 算是基础版本,不能对单元格进行样式(对齐方式、文字颜色、背景颜色等)的修饰,如果需要修饰单元格,可使用 xlsx-js-style 引入 需要导出的数据源 将数据源转成需要的二维数组 定义 Excel 表头 将定义好的表头添加到 body

    2023年04月08日
    浏览(46)
  • 前端基于XLSX实现数据导出到Excel表格,以及提示“文件已经被损坏,无法打开”的解决方法

    一、vue实现导出excel 1、前端实现 xlsx是一个用于读取、解析和写入Excel文件的JavaScript库。它提供了一系列的API来处理Excel文件。使用该库,你可以将数据转换为Excel文件并下载到本地。这种方法适用于在前端直接生成Excel文件的场景。 更多介绍可参见官网 1、安装xlsx依赖 2、引

    2024年01月23日
    浏览(84)
  • 【vue导入导出Excel】vue简单实现导出和导入复杂表头excel表格功能【纯前端版本和配合后端版本】

    前言 这是一个常用的功能,就是导入和导出excel表格 但是时常会遇到一些复杂表头的表格导出和导入 比如我这个案例里面的三层表头的表格。 网上看了下发现了一个非常简单导出和导入方法 当然这个是纯前端的版本,会出现分页不好下载的情况。所以实际工作中,导出还是

    2024年02月11日
    浏览(64)
  • 前端vue导出excel(标题加粗+表头自定义样式+表格边框+单元格自定义样式)

    接近过年,被一大堆excel报表烦死的我,遇到要求前端导出excel的后端,差点猝死的我拼命学习中,整理出这篇文章,希望看到这篇文章的你有所收获,也希望能收到大佬们的指点 之前用c#,.net弄过导出word,excel,可以点击查看.NET使用Aspose控件生成Word(可构建自定义表格)、

    2024年04月15日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包