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

实现:使用Excel.js库创建excel文件,然后再使用 file-saver库将 Excel 文件保存到用户的本地计算机。

1.安装,可以使用npm,yarn

npm install exceljs

npm install file-saver

2.封装生成excel的方法
javascript 复制代码
// 封装exceljs
const ExcelJS = require('exceljs');
const FileSaver = require('file-saver');

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
            })
        })
        this.createExcel(options)
},
    // 创建Excel文件方法
async 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 二进制数据
        FileSaver.saveAs(new Blob([buffer], { type: 'application/octet-stream' }), options.fileName)
    })

}
3.在项目中使用
javascript 复制代码
exportExcel(){
            const header = [
                ["所在部门","隐患总数","已整改隐患数","整改率","一般隐患","较大隐患","重大隐患"],
                ["","","","","隐患数","已整改数","整改中数","整改率(%)","隐患数","已整改数","整改中数","整改率(%)","隐患数","已整改数","整改中数","整改率(%)"]
            ]
            const fields = ["name","count","count_yzg","count_zgz","zgl","count_common","count_common_yzg","count_common_zgz","ybyh_zgl","count_bigger","count_bigger_yzg","count_bigger_zgz","jdyh_zgl","count_biggest","count_biggest_yzg","count_biggest_zgz","zdyh_zgl"]
            const merges = [
                //导出表格的第一行第一列,行合并2个单元格,列就用自己的一个;
                {row: 0, col: 0, rowspan: 2, colspan: 1},
                {row: 0, col: 1, rowspan: 2, colspan: 1},
                {row: 0, col: 2, rowspan: 2, colspan: 1},
                {row: 0, col: 3, rowspan: 2, colspan: 1},
                {row: 0, col: 4, rowspan: 2, colspan: 1},
                {row: 0, col: 5, rowspan: 1, colspan: 4},
                {row: 0, col: 9, rowspan: 1, colspan: 4},
                {row: 0, col: 13, rowspan: 1, colspan: 4},
            ]
            const config = this.exportConfig(header,fields,merges,this.tabledata[this.type]);//配置
            this.$utils.exportDataToExcel(config, "隐患治理情况统计表.xlsx");
        },
        //导出表格配置
        exportConfig(header = [], fields = [], merges = [], tableData = []){
            // console.log(header, fields, merges, tableData );
            // return
        //配置表头header1为一级表头,header2为二级表头,被合并的单元格为空写占位符"":
        // 如果导出前要处理数据,需要深克隆一份表格数据,然后进行处理
        const exportTableData = JSON.parse(JSON.stringify(tableData));
        const config = {
                data: exportTableData,//exportTableData为表格数据,为空的话,导出表格只显示表头
                fields: fields,
                headers: header,
                merges: merges,
                attrs: [],
                view: [],
                columnsWidth: [20, 20, 20, 20, 20,20, 20,20, 20, 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;
 }

/**

* 导出数据到Excel 传参参数

* config.data 表格数据

* config.fields 字段列表

* config.headers excel表头列表\[],可以是多级表头\['A1','B1','A2','B2']

* config.merges 需要合并的单元格,需要考虑表头的行数{row:1, col:1, rowspan: 1, colspan: 2}

* config.attrs 单元格样式配置

* config.views 工作表视图配置

* columnsWidth 每个字段列对应的宽度

* config.protect 工作表保护【此配置会保护全表,一般推荐只针对单元格进行保护配置】

* sheetName 工作表名称,默认从sheet1开始

* fileName excel文件名称

*/

相关推荐
mldong3 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排3 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60614 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角5 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!5 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰5 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi7 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen7 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马8 小时前
AI源码分析:拆解模型底层实现逻辑
前端
BillKu8 小时前
全局样式变量:CSS 自定义属性(--border-color)和SCSS 变量($border-color)的说明
javascript·css·scss