当前位置:首页 » 《关于电脑》 » 正文

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

12 人参与  2024年11月30日 08:01  分类 : 《关于电脑》  评论

点击全文阅读


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>

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


点击全文阅读


本文链接:http://zhangshiyu.com/post/194253.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1