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数组属性就有几个,不合并的表头不用管,我们只需要设置合并的表头; //如果是正常表格,只有一行标表头,无合并,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 exceljsnpm install file-saver
第二步,在assets/index.js中暴露出一个exportDataToExcel方法
这个方法跟上面的方法是基本一样的,有两个点不同:
1.引入方式不同,vue项目可以使用模块引入,
2.还有方法中一个函数的使用,最后的FileSaver.saveAs(),在HTML代码中该方法可以直接用saveAs();主要原因还是引入的方式不同而已;
下面,一样的代码我就省略了,主要写不一样的代码展示:
// 封装exceljsconst 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>
记录是为了自己日后学习和方便使用,也希望能够帮助到你;