nodejs / koa 导出带图片的excel,excel4node的使用

本文介绍如何利用Node.js库excel4node创建包含图片的Excel文件,并提供了从创建数据到设置样式及实现下载功能的完整示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、最终效果&github

github先贴出来:可以看详细配置,demo也可以直接复制粘贴试一下:

https://github.com/natergj/excel4node

最终效果整这样:

在这里插入图片描述

话不多说,我们开始实战~开冲!

二、安装excel4node

npm i excel4node

三、引入

const xl = require("excel4node");

四、创建假数据

创建三条假数据

const fishlist = [
    {
        imgUrl: path.join(__dirname, '../public/imgs/1612275667938.jpg'),
        name: "娃娃鱼",
        weight: "0.1"
    },
    {
        imgUrl: path.join(__dirname, '../public/imgs/1612275667938.jpg'),
        name: "娃娃鱼",
        weight: "0.1"
    },
    {
        imgUrl: path.join(__dirname, '../public/imgs/1612275667938.jpg'),
        name: "娃娃鱼",
        weight: "0.1"
    }
]

五、设置样式

设置每个格子中的内容水平和垂直都居中

const myStyle = {
    alignment: {
        horizontal: 'center',
        vertical: 'center'
    }
};

六、下载功能实现

1、添加表格

// 创建工作簿
const wb = new xl.Workbook();

// 创建style
const style = wb.createStyle(myStyle);

// 向工作簿添加一个表格
let ws = wb.addWorksheet('Sheet 1');

2、创建表头

ws.cell(1, 1).string('序号').style(style);	// cell(1, 1)表示excel表格中的A1
ws.cell(1, 2).string('图片').style(style);	// cell(1, 2)表示excel表格中的B1
ws.cell(1, 3).string('名称').style(style);
ws.cell(1, 4).string('重量/kg').style(style);

3、绘制表格

fishlist.forEach((item, i) => {
    // 序号
    ws.cell(3 + 4 * i, 1).number(i + 1).style(style);
    
    // 图片
    ws.addImage({
        path: item.imgUrl,
        type: 'picture',
        position: {
            type: 'twoCellAnchor',	// 双锚点定位
            from: {
                col: 2,				// 图片左上角的位置, 如果要设置一张3x3的图片,左上角设置为
                colOff: 0,			// col: 1, row: 1,右下角就为 col: 4, row: 4 
                row: 2 + 4 * i,
                rowOff: 0,
            },
            to: {
                col: 3,				// 图片右下角的位置
                colOff: 0,
                row: 5 + 4 * i,
                rowOff: 0,
            },
        },
    });
    
    // 名称
    ws.cell(3 + 4 * i, 3).string(item.name).style(style);
    
    // 重量
    ws.cell(3 + 4 * i, 4).string(item.weight).style(style);
});

4、响应下载

通过这一步,前端请求该api,便可直接下载文件,无需在服务器中创建文件

// 设置请求头, 如果直接使用http中间件,
// 可以直接调用write方法,例wire(response)即可,原理请看下面
ctx.set('Content-Length', buffer.length);

ctx.set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');

ctx.set('Content-Disposition', 'attachment; filename="' + encodeURIComponent(fileName) + '"; filename*=utf-8\'\'' + encodeURIComponent(fileName) + ';');

ctx.body = buffer;

七、完整代码

const xl = require("excel4node");

const fishlist = [
    {
        imgUrl: path.join(__dirname, '../public/imgs/1612275667938.jpg'),
        name: "娃娃鱼",
        weight: "0.1"
    },
    {
        imgUrl: path.join(__dirname, '../public/imgs/1612275667938.jpg'),
        name: "娃娃鱼",
        weight: "0.1"
    },
    {
        imgUrl: path.join(__dirname, '../public/imgs/1612275667938.jpg'),
        name: "娃娃鱼",
        weight: "0.1"
    }
]

const myStyle = {
    alignment: {
        horizontal: 'center',
        vertical: 'center'
    }
};

const downloadExcel = async (ctx, next) => {
    // 创建工作簿
    const wb = new xl.Workbook();
    const style = wb.createStyle(myStyle);
    // 向工作簿添加一个表格
    let ws = wb.addWorksheet('Sheet 1');

    ws.cell(1, 1).string('序号').style(style);
    ws.cell(1, 2).string('图片').style(style);
    ws.cell(1, 3).string('名称').style(style);
    ws.cell(1, 4).string('重量/kg').style(style);

    fishlist.forEach((item, i) => {
        ws.cell(3 + 4 * i, 1).number(i + 1).style(style);
        ws.addImage({
            path: item.imgUrl,
            type: 'picture',
            position: {
                type: 'twoCellAnchor',
                from: {
                    col: 2,
                    colOff: 0,
                    row: 2 + 4 * i,
                    rowOff: 0,
                },
                to: {
                    col: 3,
                    colOff: 0,
                    row: 5 + 4 * i,
                    rowOff: 0,
                },
            },
        });
        ws.cell(3 + 4 * i, 3).string(item.name).style(style);
        ws.cell(3 + 4 * i, 4).string(item.weight).style(style);
    });
    const fileName = "fishlist.xlsx";
    const buffer = await wb.writeToBuffer();
    ctx.set('Content-Length', buffer.length);
    ctx.set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
    ctx.set('Content-Disposition', 'attachment; filename="' + encodeURIComponent(fileName) + '"; filename*=utf-8\'\'' + encodeURIComponent(fileName) + ';');
    ctx.body = buffer;
};

module.exports = {
    downloadExcel
}

八、(不想看可以跳过)write方法的部分源码

在excel4node的源码中可以看到,当write方法传入http.ServerResponse时,会自动生成请求头并返回

 key: 'write',
        value: function write(fileName, handler) {
            var _this = this;

            builder.writeToBuffer(this).then(function (buffer) {
                switch (typeof handler === 'undefined' ? 'undefined' : _typeof(handler)) {
                    // handler passed as http response object.

                    case 'object':
                        if (handler instanceof http.ServerResponse) {
                            handler.writeHead(200, {
                                'Content-Length': buffer.length,
                                'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
                                'Content-Disposition': 'attachment; filename="' + encodeURIComponent(fileName) + '"; filename*=utf-8\'\'' + encodeURIComponent(fileName) + ';'
                            });
                            handler.end(buffer);
                        } else {
                            throw new TypeError('Unknown object sent to write function.');
                        }
                        break;

                   });
                            handler.end(buffer);
                        } else {
                            throw new TypeError('Unknown object sent to write function.');
                        }
                        break;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值