使用exceljs按照ant-table模版导入到excel表格(简略版-不带图片)

前言

平时可能会有导出到 excel 的需求,这里面直接使用 exceljs 仓库来实现导出功能,一般都是table表格导出,这里面主要介绍怎么通过数据 + antd-table column导出到 excel,图片就先不加入了,自己可以根据需要自己在了解一下即可

exceljs 地址

exceljs简介

第一步肯定是导入我们的库了

js 复制代码
const exceljs = require('exceljs');

声明一个 excel 对象,可以理解为 excel 文件本身,添加一个 worksheet,这个应该理解,每一个 excel 会有多个 sheet 表格,我们写入到其中一个就行,名字自己看着定义

创建表格、sheet

js 复制代码
const workbook = new exceljs.Workbook();
workbook.creator = '帅';
workbook.created = new Date();
// 添加工作表
const worksheet = workbook.addWorksheet('sheet1');

紧接着我们网其中一个 sheet 中添加数据就对了,多个 sheet 逻辑和单个类似,看自己需求了往后写哈,就是多几个 sheet 罢了

创建单元格标题栏(单页表头)

excel 表格样式应该都见过,是一个二维表格,长的跟 table 类似,只不过他们的表头也是单元格的一部分罢了(无论是横向还是纵向,这边以正常表格,也就是表头再上为模版开发,争取跟 table 结构一致)

我们的表头结构为 header、key、width 分别是 名称、键值、宽度,跟 table 可以说很像了

js 复制代码
const headerColumns: any[] = [];
columns.forEach((item, index) => {
    headerColumns.push({
        header: item.title,
        key: item.dataIndex,
        width: item.width ? item.width / 10 : 40, 这个像素个人尝试 / 10 差不多哈
    });
});
worksheet.columns = headerColumns;

创建单元格内容

每一行都是一个表格对象,遍历数据,将我们的数据,每组按照 key 分别放到一个对象中,每个对象就是一行,key就是列,就这样生成表格内容了

js 复制代码
const data: any[] = [];
datasource.forEach((item, index) => {
    const obj: any = {};
    columns.forEach((e, idx) => {
        const info = generateColumnKey(e, idx, item);
        obj[item.dataIndex] = item[item.dataIndex]
    });
    data.push(obj);
});
worksheet.addRows(data);

添加样式

就直说一个,我们的 第一行第一列是是索引行列,第二行是我们的标题,后面的才是我们的数据

这边以一个标题为例,获取其所在的row,然后遍历设置样式即可

js 复制代码
worksheet
    .getRow(1)
    .eachCell({ includeEmpty: true }, (cell: any, colNumber: number) => {
        cell.fill = {
            type: 'pattern',
            pattern: 'solid',
            fgColor: {
                argb: 'FFDEE6F0',
            },
        };
        cell.font = {
            size: 14,
            color: { argb: 'FF000000' }, // 黑色
            bold: true,
        };
        cell.border = {
            top: { style: 'thin' },
            left: { style: 'thin' },
            bottom: { style: 'thin' },
            right: { style: 'thin' },
        };
        cell.alignment = {
            horizontal: columns[colNumber - 1].align ?? 'left',
            vertical: 'middle',
        };
    })

实现导出功能

实际上的导出肯定跟我们想象的不一样,肯定要复杂不少,table里面又实用转化的,也就是不直接使用 dataIndex 的,那么我们可以声明一下 transform 方法接受他们的 render、renderText(前提是哪里不写 dom 节点哈,写了就没办法,转化方法只能自己再写了)

涉及到转化(render)的我们的 key 会发生变化,无法获取到内容,可以自己按照 规则声明一个唯一值即可(比如index,同一列所在索引是一样的),对于嵌套的,我们使用 reduce 取值即可,其他的直接获取内容即可,注意需要保证有值

当然最建议的是直接将 dto 转化成 vo,在一个对象,这样就不存在转化了,这里代码也会少一点,不过对于前端来说,一页就那么多数据,什么时候转化都一样,这就不强求了,如果条数非常多,那么就少点样式、提前加工好数据这样能提升一下效率

下面就是实现逻辑,自己尝试了一下,很不错

js 复制代码
export type ExcelTableColumns = {
    title: string;
    dataIndex: string | string[];
    width?: number; //实际算是文字长度了,英文1个多一点,中文两个多一点最佳,默认按照像素数量 / 10,并预留出部分空间,一般为 12-16号字体之间,这个略长一点
    align?: 'left' | 'right' | 'center';
    transform?: (value: any, record: any, index: number) => string | number; //render或者renderText,注意返回对象
};

function generateColumnKey(
    column: any,
    index: number,
    data?: any
): { key: string; value: any } {
    const info = {
        key: '',
        value: '',
    };
    if (column.transform) {
        info.key = `___transform__` + index;
        return info;
    }
    if (typeof column.dataIndex === 'string') {
        info.key = column.dataIndex;
        if (data) {
            info.value = data[column.dataIndex];
        }
    } else if (Array.isArray(column.dataIndex)) {
        info.key = column.dataIndex!.join('_');
        if (data) {
            info.value = column.dataIndex.reduce((pre: any, itm: any) => {
                return pre ? pre[itm] : '';
            }, data);
        }
    } else {
        info.key = column.dataIndex.toString();
    }
    return info;
}

//基本导出功能
export const exportExcelByTable = async (
    columns: ExcelTableColumns[],
    datasource: any[],
    filename?: string
) => {
    if (!datasource) {
        throw new Error('没有数据');
    }
    columns = columns.filter((e) => e.title && (e.transform || e.dataIndex));
    const exceljs = require('exceljs');
    const workbook = new exceljs.Workbook();
    workbook.creator = '卓朗天工';
    workbook.created = new Date();
    // 添加工作表
    const worksheet = workbook.addWorksheet('sheet1');
    const headerColumns: any[] = [];
    columns.forEach((item, index) => {
        const info = generateColumnKey(item, index);
        headerColumns.push({
            header: item.title,
            key: info.key,
            width: item.width ? item.width / 10 : 40,
        });
    });
    worksheet.columns = headerColumns;
    const data: any[] = [];
    datasource.forEach((item, index) => {
        const obj: any = {};
        columns.forEach((e, idx) => {
            const info = generateColumnKey(e, idx, item);
            obj[info.key] = e.transform
                ? e.transform(info.value, item, index)
                : info.value;
        });
        data.push(obj);
    });
    worksheet.addRows(data);
    worksheet
        .getRow(1)
        .eachCell({ includeEmpty: true }, (cell: any, colNumber: number) => {
            cell.fill = {
                type: 'pattern',
                pattern: 'solid',
                fgColor: {
                    argb: 'FFDEE6F0',
                },
            };
            cell.font = {
                size: 14,
                color: { argb: 'FF000000' }, // 黑色
                bold: true,
            };
            cell.border = {
                top: { style: 'thin' },
                left: { style: 'thin' },
                bottom: { style: 'thin' },
                right: { style: 'thin' },
            };
            cell.alignment = {
                horizontal: columns[colNumber - 1].align ?? 'left',
                vertical: 'middle',
            };
        });
    datasource.forEach((item, index) => {
        worksheet
            .getRow(index + 2)
            .eachCell(
                { includeEmpty: true },
                (cell: any, colNumber: number) => {
                    cell.fill = {
                        type: 'pattern',
                        pattern: 'solid',
                        fgColor: {
                            argb: 'FFFFFFFF',
                        },
                    };
                    cell.font = {
                        size: 12,
                        color: { argb: 'FF000000' }, // 黑色
                    };
                    cell.border = {
                        top: { style: 'thin' },
                        left: { style: 'thin' },
                        bottom: { style: 'thin' },
                        right: { style: 'thin' },
                    };
                    cell.alignment = {
                        horizontal: columns[colNumber - 1].align ?? 'left',
                        vertical: 'middle',
                    };
                }
            );
    });
    const buffer = await workbook.xlsx.writeBuffer();
    saveFile(buffer, filename);//文件导出
};

导出到文件功能,通过 a 标签实现下载

js 复制代码
const saveFile = (data: any, filename?: string) => {
    const blob = new Blob([data], {
        type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8',
    }) as any;
    const url = URL.createObjectURL(blob);
    const aLink = document.createElement('a');
    aLink.setAttribute(
        'download',
        filename ? filename : `${new Date().getTime()}.xlsx`
    );
    aLink.setAttribute('href', url);
    document.body.appendChild(aLink);
    aLink.click();
    document.body.removeChild(aLink);
    URL.revokeObjectURL(blob);
};

从我们的 table-column 到 excel 可能还需要一些操作,我们直接在转化一下吧,例如前面加个索引,还有类型不一样,加个类型强转

js 复制代码
export const exportExcelByTableCustom = async (
    columns: Record<string, any>[],
    datasource: any[],
    filename: string,
    no?: boolean | number
) => {
    const cols = columns.map((e: any) => {
        const transform = e.render
            ? e.render
            : e.renderText
              ? e.renderText
              : undefined;
        return {
            title: e.title,
            dataIndex: e.dataIndex,
            width: e.width ?? 300,
            align: e.align,
            transform,
        } as ExcelTableColumns;
    });
    no &&
        cols.unshift({
            title: 'No.',
            width: no === true ? 60 : no,
            align: 'center',
            transform: (_, __, index: number) => index + 1,
        } as ExcelTableColumns);
    await exportExcelByTable(cols, datasource, filename);
};

到上面一步基本可以直接用了

最后

如果有复用要求,可以写一个带接口的,如果接口分页处理,那么一页一页遍历处理的可以直接写好,如果是一次获取所有的,那就更简单了哈

相关推荐
冰心孤城3 小时前
Excel: xls与xlsx格式转换排坑指南
java·前端·excel
金豆呀7 小时前
WPS批量提取Word文档内容生成固定格式Excel表格
word·excel·wps
Access开发易登软件8 小时前
Access 怎么做前后端分离?用 Web API 读写 SQL Server
前端·数据库·人工智能·microsoft·excel·access
红莲凪是1 天前
使用二次封装的Excel COM 组件操作Excel\WPS ET IExcelRange 高级应用
python·excel·wps
用户298698530141 天前
如何使用免费工具在线将 Excel 转换为 XML 格式
人工智能·后端·excel
开开心心就好1 天前
内存清理工具定时自动清理开机自启动
java·开发语言·elasticsearch·ocr·excel·音视频·big data
开开心心就好1 天前
电脑内存优化工具一键释放内存超简单
java·开发语言·macos·arcgis·ocr·excel·音视频
随手工具-Excel, pdf, SQL1 天前
没有 SSMS 导入向导?Excel/CSV 一键生成 SQL Server INSERT 脚本
excel·sql server·在线工具·insert·测试数据·ssms·t-sql
SunnyDays10112 天前
Python 将 Excel(XLS/XLSX)转换为 JSON:导出工作簿、工作表、单元格区域与自定义 JSON 结构
python·json·excel·excel 转 json·导出 excel 到 json·xlsx 转 json·xls 转 json
chatexcel2 天前
ChatExcel AI Word 升级:多模态读资料、按模板生成、智能排版配图,还能批注修订和联动Excel 复核
人工智能·ai·word·excel·ai写作