用exceljs和file-saver插件实现纯前端表格导出Excel(支持样式配置,多级表头)

exceljs在Jquery(HTML)和vue项目中实现导出功能

  • 前言
  • Jquery(HTML)中实现导出
      • 第一步,先在项目本地中导入exceljs和file-saver包
      • 第二步,封装导出Excel方法(可直接复制粘贴使用)
      • 第三步,在项目中使用
  • vue中实现导出
      • 第一步,还是先安装,可以使用npm,yarn,pnpm,都可以
      • 第二步,在assets/index.js中暴露出一个exportDataToExcel方法
      • 第三步,项目中的使用

前言

最近,做公司一个老项目(jquery),有个需求是将表格中的json数据,导出为Excel文件,表格表头还是动态多层级,导出的excel样式和项目中表格一致;

老项目中之前用的都是xlsx插件,我查询了一下文章,也看到过用xlsx实现多层表头下载,但是感觉比较麻烦,看到推荐使用exceljs插件比较方便;就了解一下,用在项目中得以实现;

话不多说,上案例图:
在这里插入图片描述
导出excel效果:
在这里插入图片描述

这个案例我主要演示的是两层分组表头和样式配置的代码;如果要想仔细研究该插件,可以阅读 Exceljs官方文档;

怎么使用,下面记录非常详情,每一步代码还有注释解析,方便自己和大家理解

Jquery(HTML)中实现导出

第一步,先在项目本地中导入exceljs和file-saver包

在这里插入图片描述
在这里插入图片描述
以上插件包,也可以 npm install exceljs ,npm install file-saver获取,执行命令后项目中会多一个node_modules包,然后找到这两个文件复制出来放到项目中,然后删除无用的node_modules,和pakege.json文件;

第二步,封装导出Excel方法(可直接复制粘贴使用)

在项目中创建assets文件,新建一个exportDataToExcel.js文件

   /*** 导出数据到Excel方法* @param {Array[Object]} config.data 表格数据* @param {Array[String]} config.fields 字段列表* @param {Array[String]} config.headers excel表头列表[[]],可以是多级表头[['A1','B1'],['A2','B2']]* @param {Array[Object]} config.merges 需要合并的单元格,需要考虑表头的行数[{row:1, col:1, rowspan: 1, colspan: 2}]* @param {Array[Object]} config.attrs 单元格样式配置* @param {Array[Object]} config.views 工作表视图配置* @param {Array[Number]} columnsWidth 每个字段列对应的宽度* @param {Object} config.protect 工作表保护【此配置会保护全表,一般推荐只针对单元格进行保护配置】* @param {String} sheetName 工作表名称,默认从sheet1开始* @param {String} fileName excel文件名称*/function exportDataToExcel(config, fileName) {if (!config) return;const options = {fileName: fileName || `导出excel文件【${Date.now()}】.xlsx`,worksheets: []}if(!Array.isArray(config)) {config = [config]}config.forEach((item) => {// 深拷贝data【JSON.stringify有缺陷,可自行换成_.cloneDeep】const data = JSON.parse(JSON.stringify(item.data));const results = data.map(obj => {return item.fields.map(key => {return obj[key]})})// 生成完整excel数据let excelData = [];excelData = excelData.concat(item.headers).concat(results);// 单元格合并处理【excel数据的第一行/列是从1开始】let excelMerges = [];excelMerges = item.merges.map(m => {return [m.row + 1, m.col + 1, m.row + m.rowspan, m.col + m.colspan]})// 单元格配置处理 excel数据的第一行/列是从1开始】let excelAttrs = [];excelAttrs = item.attrs.map(attr => {attr.rowStart += 1;attr.rowEnd += 1;attr.colStart += 1;attr.colEnd += 1;return attr})options.worksheets.push({data: excelData,merges: excelMerges,attrs: excelAttrs,views: item.views,columnsWidth: item.columnsWidth,protect: item.protect,sheetName: item.sheetName})})createExcel(options)}// 创建Excel文件方法async  function createExcel(options) {if (!options.worksheets.length) return;// 创建工作簿const workbook = new ExcelJS.Workbook();for (let i = 0; i < options.worksheets.length; i++) {const sheetOption = options.worksheets[i];// 创建工作表const sheet = workbook.addWorksheet(sheetOption.sheetName || 'sheet' + (i + 1));// 添加数据行sheet.addRows(sheetOption.data);// 配置视图sheet.views = sheetOption.views;// 单元格合并处理【开始行,开始列,结束行,结束列】if (sheetOption.merges){sheetOption.merges.forEach((item) => {sheet.mergeCells(item) });}// 工作表保 if (sheetOption.protect) {const res = await sheet.protect(sheetOption.protect.password, sheetOption.protect.options);}// 单元格样式处理if (sheetOption.attrs.length) {sheetOption.attrs.forEach((item) => {const attr = item.attr || {};// 获取开始行-结束行; 开始列-结束列const rowStart = item.rowStart;const rowEnd = item.rowEnd;const colStart = item.colStart;const colEnd = item.colEnd;if (rowStart) { // 设置行for (let r = rowStart; r <= rowEnd; r++) {// 获取当前行const row = sheet.getRow(r);if (colStart) { // 列设置for (let c = colStart; c <= colEnd; c++) {// 获取当前单元格const cell = row.getCell(c);Object.keys(attr).forEach((key) => {// 给当前单元格设置定义的样式cell[key] = attr[key];});}} else {// 未设置列,整行设置【大纲级别】Object.keys(attr).forEach((key) => {row[key] = attr[key];});}}} else if (colStart) { // 未设置行,只设置了列for (let c = colStart; c <= colEnd; c++) {// 获取当前列,整列设置【大纲级别】const column = sheet.getColumn(c);Object.keys(attr).forEach((key) => {column[key] = attr[key];});}} else {// 没有设置具体的行列,则为整表设置Object.keys(attr).forEach((key) => {sheet[key] = attr[key];});}})}// 列宽设置if (sheetOption.columnsWidth) {for (let i = 0; i < sheet.columns.length; i++) {sheet.columns[i].width = sheetOption.columnsWidth[i]}}}// 生成excel文件workbook.xlsx.writeBuffer().then(buffer => {// application/octet-stream 二进制数据saveAs(new Blob([buffer], { type: 'application/octet-stream' }), options.fileName)})
} 

第三步,在项目中使用

在HTML中使用,不能使用模块导入,只能通过< script >标签引入;

<!DOCTYPE html>
<html lang="en">
<head>//引入我们放入项目的文件的的压缩js文件<script src="/static/exceljs/dist/exceljs.min.js"></script><script src="/static/file-saver/dist/FileSaver.min.js"></script>//引入封装导出Excel方法<script src="/static/assets/exportDataToExcel.js"></script>
</head>
<body>
<script>
//表格数据var exportTableData = [{name:'张三',sexy:'男',age:22,hobby:'篮球',provices:'河南省',city:'郑州',status:'未婚'},{name:'李四',sexy:'女',age:23,hobby:'排球',provices:'北京市',city:'北京市',status:'未婚'},{name:'王二',sexy:'男',age:28,hobby:'足球',provices:'山东省',city:'青岛',status:'已婚'},]//点击导出按钮事件function onExport() {let config = exportConfig();exportDataToExcel(config, "人员信息表.xlsx");}//导出表格配置function  exportConfig(){//配置表头header1为一级表头,header2为二级表头,被合并的单元格为空写占位符""://这是实现导出多级表头的关键两点的中的第一点,分几层表头写几个header;const header1 = ["姓名", "个人信息","","","居住城市","","婚姻状况"];const header2 = ["","性别","年龄","爱好","省份","城市",""];//表格展示字段,顺序要正确const fields =  ["name", "sexy","age","hobby","provices","city","status"]//这是实现导出多级表头的关键两点的中的第二点,合并表头单元格;//row:代表行,col:代表列,rowspan:代表合并行数,colspan:代表合并列数,//也就是表头有几个要合并单元格的属性,merges数组属性就有几个;const merges = [//导出表格的第一行第一列,行合并2个单元格,列就用自己的一个;{row: 0, col: 0, rowspan: 2, colspan: 1},//导出表格的第一行第二列,行合并1个单元格,列合并3个单元格;{row: 0, col: 1, rowspan: 1, colspan: 3},{row: 0, col: 4, rowspan: 1, colspan: 2},{row: 0, col: 6, rowspan: 2, colspan: 1},]// 如果导出前要处理数据,需要深克隆一份表格数据,然后进行处理exportTableData = JSON.parse(JSON.stringify(exportTableData));const config = {data: exportTableData,//exportTableData为表格数据,为空的话,导出表格只显示表头fields:fields,headers: [header1, header2],merges: merges,attrs: [],view: [],columnsWidth: [20, 20, 20, 20, 20,20, 20,],//每行列的宽// protect: {},sheetName: "个人信息"};// 设置全表单元格边框,居中布局config.attrs.push({rowStart: 0,rowEnd: config.data.length + 1,//表格表头多几层,就加几个colStart: 0,colEnd: config.fields.length - 1,attr: {alignment: { vertical: "middle", horizontal: "center" },border: {top: { style: "thin" },left: { style: "thin" },bottom: { style: "thin" },right: { style: "thin" }}}});// 设置表头填充颜色,字体加粗config.attrs.push({rowStart: 0,rowEnd: 1,//表格表头多几层,就写几colStart: 0,colEnd: config.fields.length - 1,attr: {fill: {type: "pattern",pattern: "solid",fgColor: { argb: "c5c8ce" }},font: {bold: true}}});return config;}
</script>
</body
</html>

vue中实现导出

第一步,还是先安装,可以使用npm,yarn,pnpm,都可以

npm install exceljs
npm install file-saver

第二步,在assets/index.js中暴露出一个exportDataToExcel方法

这个方法跟上面的方法是基本一样的,有两个点不同:
1.引入方式不同,vue项目可以使用模块引入,
2.还有方法中一个函数的使用,最后的FileSaver.saveAs(),在HTML代码中该方法可以直接用saveAs();主要原因还是引入的方式不同而已;

下面,一样的代码我就省略了,主要写不一样的代码展示:

// 封装exceljs
const ExcelJS = require('exceljs');
const FileSaver = require('file-saver');export function exportDataToExcel(config, fileName){
...
}async function createExcel(options){
...// 生成excel文件workbook.xlsx.writeBuffer().then(buffer => {// application/octet-stream 二进制数据FileSaver.saveAs(new Blob([buffer], { type: 'application/octet-stream' }), options.fileName)})
}

第三步,项目中的使用

把第二步写的方法在项目中导入;

<script>import { exportDataToExcel } from "../assets/index.js";data() {return {exportTableData:[{name:'张三',sexy:'男',age:22,hobby:'篮球',provices:'河南省',city:'郑州',status:'未婚'},{name:'李四',sexy:'女',age:23,hobby:'排球',provices:'北京市',city:'北京市',status:'未婚'},{name:'王二',sexy:'男',age:28,hobby:'足球',provices:'山东省',city:'青岛',status:'已婚'},]};},methods:{onExport(){const config = this.exportConfig();exportDataToExcel(config, "人员信息表.xlsx");},//该方法和上面在HTML中的一样exportConfig(){...}}</script>

记录是为了自己日后学习和方便使用,也希望能够帮助到你;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/400919.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java 实现 B树(通俗易懂)

目录 一.概念 二.节点定义 三.插入操作 1.查找位置 2.插入 3.分裂 四.B树和B*树 1.B树 2.B*树 一.概念 B树是一颗多叉平衡树&#xff0c;空树也是多叉平衡树。 一颗M阶的B树要满足以下条件&#xff1a; 1.根节点至少有两个孩子&#xff1b; 2.每个非根节点至少有(上…

机械学习—零基础学习日志(如何理解线性代数2)

零基础为了学人工智能&#xff0c;正在快乐学习&#xff0c;每天都长脑子 引言 在平面中&#xff0c;直线的定义可以理解为&#xff0c;任意缩放同一个平面向量得到所有点的集合。 所以要得到一个三维空间中的直线&#xff0c;只需要将这个向量改成三维向量即可。 什么是线…

uniapp加载第三方字体方案对比(附原生微信小程序方案)

文章目录 官方文档uniapp文档微信小程序文档 下载字体包引入方案限制微信小程序限制uniapp的限制 方案对比方案1&#xff1a;CSS本地加载方案2&#xff1a;CSS远程加载方案3&#xff1a;转换为base64&#xff0c;然后通过css引入方案4&#xff1a;使用uni.loadFontFace() 页面使…

(Jmeter、Fiddler)脚本转换Loadrunner脚本

背景&#xff1a;公司政治任务、各种体系文档要留档&#xff0c;但有些不在体系内的工具生成的脚本需要转化到体系内以备留档。 一、Loadrunner代理设置 开始录制配置&#xff1a; Record->Remote Application via LoadRunner Proxy LoadRrunner Proxy listens on port-…

米联客-FPGA程序设计Verilog语法入门篇连载-19 Verilog语法_低功耗设计

软件版本&#xff1a;无 操作系统&#xff1a;WIN10 64bit 硬件平台&#xff1a;适用所有系列FPGA 板卡获取平台&#xff1a;https://milianke.tmall.com/ 登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑&#xff01; 1概述 本小节讲解Verilog语法的低功…

Spark MLlib 特征工程(下)

Spark MLlib 特征工程(下) 前面我们提到&#xff0c;典型的特征工程包含如下几个环节&#xff0c;即预处理、特征选择、归一化、离散化、Embedding 和向量计算&#xff0c;如下图所示。 在上一讲&#xff0c;我们着重讲解了其中的前 3 个环节&#xff0c;也就是预处理、特征选…

java---概念

一.配置环境&#xff08;三个变量&#xff09; 1.JAVA_HOME&#xff08;记录Java安装文件的路径&#xff09; 2.PATH&#xff08;系统直找的路径&#xff09; 3.CLASSPATH&#xff08;Java程序路径&#xff09; .;%JAVA_HOME%\lib 二.第一个Java程序 源代码&#xff1a; so…

使用kimi快速完成论文仿写的提示词,我帮你总结好了

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 在完成论文写作时&#xff0c;很多人都会想到“仿写”&#xff0c;但正确的做法是借鉴而非复制。今天我们将分享如何利用Kimi智能助手来提高论文写作的效率和质量&#xff0c;同时确保原…

Kubernetes快速入门

一、容器集群管理概述 1.1背景概述 容器技术的诞生虽解决了应用打包和发布的难题&#xff0c;但单一的容器技术工具并无 法支持起生产级大规模容器部署的场景。针对这一场景&#xff0c;容器管理与编排成为了容器技术发展的关键。Kubernetes 便是在这样的大背景下诞生的。 1.2…

【博客23】缤果Android_XXX调试助手模板(3款)V1.0(中级篇)

超级好用的Android_XXX调试助手模板 ( Android Studio Java) 备注: 仅模板无通信协议 开发工具: android-studio-2024.1.1.12-windows.exe 目录 一、软件概要&#xff1a; 二、软件界面&#xff1a; 1.App演示 2.其他扩展展示 2.1 自定义指令集 2.2 修改自定义指令集 …

IAM 编程访问和 AWS CLI

添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; IAM 编程访问&#xff08;欢迎来到雲闪世界。&#xff09; IAM 编程访问是指使用访问密钥通过 API 和命令行工具访问 AWS 服务和资源。 当您为 IAM 用户启用编程访问时&#xff0c;您将生成可用于验证和…

Java-自定义注解中成员变量是Class<?>

在Java中,自定义注解可以包含各种类型的成员变量,包括 Class<?> 类型。这种类型的成员变量 通常用于表示某个类的类型信息。下面我将详细介绍如何定义一个包含 Class<?> 类型成员变量的 自定义注解,并给出一些示例代码。 1. 定义自定义注解 定义一个自定义…

行业大模型:信用评分大模型、生产优化大模型、库存管理大模型、物流行业大模型、零售行业大模型

金融行业大模型&#xff1a;信用评分大模型 信用评分模型在金融行业中扮演着至关重要的角色&#xff0c;它通过对个人或企业的信用状况进行评估&#xff0c;帮助金融机构有效控制风险&#xff0c;提高业务效率。以下是信用评分模型的特点及案例介绍&#xff1a; 信用评分模型…

高阶数据结构——B树

1. 常见的搜索结构 以上结构适合用于数据量相对不是很大&#xff0c;能够一次性存放在内存中&#xff0c;进行数据查找的场景。如果数据量很大&#xff0c;比如有100G数据&#xff0c;无法一次放进内存中&#xff0c;那就只能放在磁盘上了&#xff0c;如果放在磁盘上&#xff0…

[Unity]在场景中随机生成不同位置且不重叠的物体

1.前言 最近任务需要用到Unity在场景中随机生成物体&#xff0c;且这些物体不能重叠&#xff0c;简单记录一下。 参考资料:How to ensure that spawned targets do not overlap ? 2.结果与代码 结果如下所示&#xff1a; 代码如下所示&#xff1a; using System.Collec…

Java练习模拟考试答题系统小程序源码

&#x1f31f;高效备考秘籍&#xff01;如何玩转练习模拟考试答题系统✨ &#x1f4da; 引言&#xff1a;为什么选择模拟考试&#xff1f; 嘿小伙伴们&#xff0c;是不是每次临近大考都紧张得不行&#xff1f;别怕&#xff0c;今天就来揭秘一个备考神器——练习模拟考试答题系…

React使用useRef ts 报错

最近在写自己的React项目&#xff0c;我在使用useRef钩子函数的时候发现 TS2322: Type MutableRefObject<HTMLDivElement | undefined> is not assignable to type LegacyRef<HTMLDivElement> | undefined Type MutableRefObject<HTMLDivElement | undefined&g…

C++STL初阶(10):list的简易实现(下)

在上一文中我们完成了链表的多数基本接口&#xff0c;本文主要围绕构造函数进行补充 1. 链表的拷贝 在前文中我们没有手动实现拷贝构造&#xff0c;所以使用的就是编译器自动生成的浅拷贝 先使用一下编译器自动生成的浅拷贝&#xff1a; 我们在打印li2之前给li1加入一个数据&…

excel导入

Excel数据导入 使用easyexcel和hutool-poi实现excel导入 1、pom依赖 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.6</version></dependency><dependency><groupId…

【笔记】Swin-Transformer 的计算量与Transformer的计算量的对比:前者通过使用新颖的窗口技巧,将后者的高阶项变为低阶,大大降低了计算量

补充1&#xff1a; 局部窗口内的自注意力&#xff08;W-MSA&#xff09;: 在 Swin Transformer 中&#xff0c;输入特征图被划分为多个小的窗口&#xff08;例如 7x7 的窗口&#xff09;。在每个窗口内&#xff0c;计算自注意力机制&#xff08;W-MSA, Window-based Multi-Head…