Vue3中使用exceljs和file-saver实现Excel导出(含图片导出)功能完整方案
作者:叫我OldFe
ExcelJS是一个用于在Node.js和浏览器中创建、读取和修改Excel文件的强大JavaScript库,这篇文章主要介绍了Vue3中使用exceljs和file-saver实现Excel导出(含图片导出)功能的相关资料,需要的朋友可以参考下
问题背景
在Vue3项目中,当我们需要将包含图片的数据导出到Excel时,常用的sheetjs/xlsx
库存在局限性:无法直接导出图片到单元格。本文将提供完整的解决方案,封装可直接复用的工具函数。
解决方案
技术选型
使用exceljs
+ file-saver
组合:
exceljs
:支持图片插入的Excel操作库file-saver
:前端文件保存工具
功能特性
✅ 支持多图片列导出
✅ 自动识别Base64和DataURL格式
✅ 精确控制图片位置
✅ 异常处理与性能优化
完整实现代码
步骤1:安装依赖
npm install exceljs file-saver
步骤2:创建工具文件
// utils/excelExport.js import ExcelJS from 'exceljs'; import { saveAs } from 'file-saver'; /** * * @param headers 表头,[表头1,表头2,...] 必填 * @param tableData 内容 [data1,data2,...] 必填 * @param imageIndex 图片下标列 [0, 1, 2 , ...], 非必填 * @returns {Promise<void>} */ export const exportToExcel = async (headers, tableData, imageIndex = []) => { const workbook = new ExcelJS.Workbook(); const worksheet = workbook.addWorksheet('Sheet1'); // 添加表头 const headerRow = worksheet.addRow(headers); // 设置表头样式 headerRow.eachCell((cell) => { cell.font = { bold: true, color: { argb: 'FFFFFFFF' }, size: 12 }; cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF007BFF' } }; cell.alignment = { horizontal: 'center', vertical: 'middle' }; }); // 设置列宽 headers.forEach((_, colIndex) => { let width = 20; // 默认列宽 if (imageIndex.includes(colIndex)) { width = 30; // 图片列更宽 } worksheet.getColumn(colIndex + 1).width = width; }); // 处理数据行(修改为异步) for (let rowIdx = 0; rowIdx < tableData.length; rowIdx++) { const row = tableData[rowIdx]; const dataRow = worksheet.addRow(row); if (imageIndex.length > 0) { // 使用Promise.all处理多列图片 await Promise.all(imageIndex.map(async (colIdx) => { const imgUrl = row[colIdx]; if (!imgUrl) return; try { const parsed = await parseImageData(imgUrl); if (!parsed) return; const imageId = workbook.addImage({ base64: parsed.base64, extension: parsed.extension, }); const colLetter = getExcelColumnLetter(colIdx); const excelRow = rowIdx + 2; worksheet.addImage(imageId, { tl: { col: colIdx, row: excelRow - 1 }, br: { col: colIdx + 1, row: excelRow }, editAs: 'oneCell' // 更稳定的定位方式 }); } catch (error) { console.error(`图片处理失败(行${rowIdx + 1}列${colIdx + 1}):`, error); } })); } } // 生成文件 const buffer = await workbook.xlsx.writeBuffer(); saveAs(new Blob([buffer]), `数据导出_${new Date().getTime()}.xlsx`); }; // 列索引转Excel字母(如:0 -> A, 1 -> B) const getExcelColumnLetter = (column) => { let letter = ''; let col = column + 1; while (col > 0) { const remainder = (col - 1) % 26; letter = String.fromCharCode(65 + remainder) + letter; col = Math.floor((col - 1) / 26); } return letter; }; // 新增:将图片URL转换为base64 const urlToBase64 = async (url) => { try { const response = await fetch(url); const blob = await response.blob(); return new Promise((resolve) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result); reader.readAsDataURL(blob); }); } catch (error) { console.error('图片转换失败:', error); return null; } }; // 修改后的解析函数 const parseImageData = async (imgData) => { if (!imgData) return null; // 处理URL情况 if (imgData.startsWith('http')) { const dataURL = await urlToBase64(imgData); if (!dataURL) return null; const [header, base64] = dataURL.split(';base64,'); const extension = header.split('/')[1]; return { base64, extension }; } // 原有处理dataURL的逻辑 if (imgData.startsWith('data:image')) { const [header, base64] = imgData.split(';base64,'); if (!header || !base64) return null; const extension = header.split('/')[1]; return { base64, extension }; } return null; };
使用示例
Vue3组件调用
<template> <button @click="handleExport">导出Excel</button> </template> <script setup> import { exportDataToExcel } from '@/utils/excelExport'; const headers = ['名称', '价格', '主图']; const tableData = [ ['商品A', 99.9, 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg'], ['商品B', 199.9, ''] ]; const imageIndex = [2]; // 第三列为图片列 const handleExport = async () => { await exportDataToExcel(headers, tableData, imageIndex); }; </script>
扩展配置
设置列宽
headers.forEach((_, colIndex) => { let width = 20; // 默认列宽 if (imageIndex.includes(colIndex)) { width = 30; // 图片列更宽 } worksheet.getColumn(colIndex + 1).width = width; });
设置表头样式
headerRow.eachCell((cell) => { cell.font = { bold: true, color: { argb: 'FFFFFFFF' }, size: 12 }; cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF007BFF' } }; cell.alignment = { horizontal: 'center', vertical: 'middle' }; });
导出样式
注意事项
图片规范
- 建议使用PNG格式
- 单图片尺寸不超过500x500px
- Base64字符串需完整
性能建议
- 推荐数据量:<1000行
- 单文件图片:<50张
- 大文件建议分页导出
常见问题
- 图片不显示:检查Base64格式是否正确
- 位置偏移:调整
tl
/br
定位参数 - 内存溢出:分批次处理数据
实现原理
坐标转换
通过getExcelColumnLetter
函数将数字索引转换为Excel字母坐标图片处理
- 自动剥离DataURL头信息
- 支持纯Base64直接使用
定位系统
// tl: 左上角定位(top-left) // br: 右下角定位(bottom-right) { tl: { col: 0, row: 0 }, // A1单元格 br: { col: 1, row: 1 } // B2单元格 }
总结
本文提供的方案具有以下优势:
- 开箱即用:封装完整工具函数
- 灵活配置:支持多图片列、自定义样式
- 健壮性强:完善的异常处理机制
建议根据实际业务需求调整图片定位参数和样式配置,对于复杂报表建议结合后端生成方案。
到此这篇关于Vue3中使用exceljs和file-saver实现Excel导出(含图片导出)功能的文章就介绍到这了,更多相关Vue3导出Excel内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!