简介:本文详细介绍如何使用ExcelJS库将Ant Design的Table组件数据按照预设模板导出为Excel文件,涵盖模板设计、数据填充、样式优化等核心环节,提供完整的代码实现方案。
在Web开发中,将前端表格数据导出为Excel是常见需求。Ant Design的Table组件提供了丰富的数据展示功能,但原生不支持直接导出为带有复杂样式的Excel文件。ExcelJS作为一款功能强大的Node.js库,能够精确控制Excel文件的单元格样式、合并区域、公式计算等特性,非常适合实现模板化导出。
典型应用场景包括:
与xlsx等库相比,ExcelJS的优势在于:
npm install exceljs antd @ant-design/icons# 或使用yarnyarn add exceljs antd @ant-design/icons
优秀模板应具备:
建议采用分层设计:
const templateConfig = {sheetName: '业务数据',headerRange: 'A1:F1', // 表头区域dataRange: 'A2:F100', // 数据预留区域footerRange: 'A101:F101', // 页脚区域styles: {header: { /* 样式定义 */ },data: { /* 样式定义 */ },footer: { /* 样式定义 */ }}};
const ExcelJS = require('exceljs');const { Table } = require('antd');async function exportToExcel(tableData, templatePath) {const workbook = new ExcelJS.Workbook();// 加载模板或新建工作簿if (templatePath) {await workbook.xlsx.readFile(templatePath);} else {const sheet = workbook.addWorksheet('Sheet1');// 初始化模板结构...}const worksheet = workbook.getWorksheet('业务数据');// 填充表头(示例)const headerRow = worksheet.getRow(1);headerRow.values = ['序号', '名称', '数量', '单价', '金额', '备注'];// 填充数据tableData.forEach((item, index) => {const row = worksheet.getRow(index + 2);row.values = [index + 1,item.name,item.quantity,item.price,item.quantity * item.price,item.remark];});// 自动调整列宽worksheet.columns.forEach(column => {let maxLength = 0;column.eachCell({ includeEmpty: true }, cell => {const columnLength = cell.value ? cell.value.toString().length : 0;if (columnLength > maxLength) {maxLength = columnLength;}});column.width = maxLength < 10 ? 10 : maxLength + 2;});// 生成Excel文件const buffer = await workbook.xlsx.writeBuffer();// 后续处理(如触发下载)...}
// 应用表头样式function applyHeaderStyle(row) {row.eachCell(cell => {cell.font = { bold: true, color: { argb: 'FFFFFF' } };cell.fill = {type: 'pattern',pattern: 'solid',fgColor: { argb: '4472C4' }};cell.border = {top: { style: 'thin' },left: { style: 'thin' },bottom: { style: 'thin' },right: { style: 'thin' }};cell.alignment = { vertical: 'middle', horizontal: 'center' };});}// 应用数据行样式function applyDataStyle(row, isOdd) {row.eachCell(cell => {cell.border = {top: { style: 'thin' },left: { style: 'thin' },bottom: { style: 'thin' },right: { style: 'thin' }};cell.alignment = { vertical: 'middle' };});if (isOdd) {row.eachCell(cell => {cell.fill = {type: 'pattern',pattern: 'solid',fgColor: { argb: 'EDEDED' }};});}}
// 在Ant-Table组件中const [dataSource, setDataSource] = useState([]);const [selectedRowKeys, setSelectedRowKeys] = useState([]);const columns = [{ title: '名称', dataIndex: 'name', key: 'name' },{ title: '数量', dataIndex: 'quantity', key: 'quantity' },// 其他列定义...];// 导出按钮处理const handleExport = () => {// 获取当前显示数据(可添加筛选条件)const exportData = dataSource.filter(item =>selectedRowKeys.includes(item.key) || selectedRowKeys.length === 0);exportToExcel(exportData);};
function mapAntColumnsToExcel(antColumns) {return antColumns.map(col => ({header: col.title,key: col.dataIndex,width: col.width ? col.width / 7.5 : 15, // 近似转换style: col.className ? getStyleByClassName(col.className) : null}));}// 在导出函数中使用const excelColumns = mapAntColumnsToExcel(columns);
分块写入:对于超过10万行数据,采用流式写入
async function exportLargeData(data, chunkSize = 5000) {const workbook = new ExcelJS.Workbook();const sheet = workbook.addWorksheet('大数据');// 写入表头...for (let i = 0; i < data.length; i += chunkSize) {const chunk = data.slice(i, i + chunkSize);chunk.forEach((item, index) => {const rowIdx = i + index + 2; // +2因为表头占1行,索引从0开始const row = sheet.getRow(rowIdx);// 填充数据...});// 定期保存(浏览器环境需特殊处理)if (i % (chunkSize * 5) === 0) {console.log(`已处理 ${i} 条数据`);}}// 最终写入...}
// 应用样式
sheet.getCell(‘D2’).numFmt = styleTemplates.currency.numFmt;
# 四、常见问题解决方案## 1. 中文乱码问题- 解决方案:确保文件以UTF-8编码保存,并设置正确的字体```javascriptworkbook.creator = 'My App';workbook.created = new Date();// 设置中文字体workbook.eachSheet((sheet, id) => {sheet.columns.forEach(column => {column.style = { font: { name: '微软雅黑', family: 2 } };});});
// 前端导出实现function downloadExcel(buffer, fileName = '导出数据.xlsx') {const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });const url = URL.createObjectURL(blob);const a = document.createElement('a');a.href = url;a.download = fileName;a.click();URL.revokeObjectURL(url);}// 在async函数中调用const buffer = await workbook.xlsx.writeBuffer();downloadExcel(buffer);
// 合并表头示例worksheet.mergeCells('A1:B1');const mergedCell = worksheet.getCell('A1');mergedCell.value = '基本信息';mergedCell.alignment = { horizontal: 'center', vertical: 'middle' };// 动态合并相同内容单元格function mergeSameCells(sheet, columnKey, startRow = 2) {let mergeStart = null;let prevValue = null;for (let i = startRow; i <= sheet.rowCount; i++) {const cell = sheet.getCell(`${columnKey}${i}`);if (cell.value === prevValue) {if (!mergeStart) mergeStart = i - 1;} else {if (mergeStart !== null && i - 1 > mergeStart) {sheet.mergeCells(`${columnKey}${mergeStart + 1}:${columnKey}${i - 1}`);}mergeStart = null;prevValue = cell.value;}}}
try {await exportToExcel(data);} catch (error) {console.error('导出失败:', error);message.error('导出失败,请重试');}
通过以上方法,开发者可以高效实现Ant-Table数据到Excel的模板化导出,既保持前端展示的一致性,又满足业务对Excel文件格式的严格要求。实际项目中,建议结合具体业务场景进行定制化开发,建立可复用的导出组件库。