react中实现导出excel文件
- 一、安装依赖
- 二、实现导出功能
- 三、自定义列标题
- 四、设置列宽度
- 五、样式优化
- 1、安装扩展库
- 2、设置样式
- 3、扩展样式功能
在 React 项目中实现点击按钮后导出数据为 Excel 文件,可以使用 xlsx 和 file-saver 这两个库。
一、安装依赖
在项目中安装必要的库:
npm install xlsx file-saver
- xlsx:用于生成 Excel 文件。
- file-saver:用于触发文件下载。
二、实现导出功能
import React from 'react';
import * as XLSX from 'xlsx'; // 用于操作 Excel 文件
import { saveAs } from 'file-saver'; // 用于保存文件
const ExportExcel = () => {
const handleExport = () => {
// 示例数据
const data = [
{ Name: 'John Doe', Age: 28, City: 'New York' },
{ Name: 'Jane Smith', Age: 34, City: 'San Francisco' },
{ Name: 'Sam Green', Age: 45, City: 'Chicago' },
];
// 将数据转换为工作表
const worksheet = XLSX.utils.json_to_sheet(data);
// 创建一个新的工作簿
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
// 导出为 Blob
const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
const blob = new Blob([excelBuffer], { type: 'application/octet-stream' });
// 使用 FileSaver 保存文件
saveAs(blob, 'example.xlsx');
};
return (
<div>
<button onClick={handleExport}>导出 Excel</button>
</div>
);
};
export default ExportExcel;
三、自定义列标题
在使用 xlsx 时,如果需要自定义列标题,可以通过手动创建数据表头,然后将其与数据合并为新的数组,最后生成工作表。
import React from 'react';
import * as XLSX from 'xlsx'; // 用于操作 Excel 文件
import { saveAs } from 'file-saver'; // 用于保存文件
const ExportExcelWithHeaders = () => {
const handleExport = () => {
// 示例数据
const data = [
{ name: 'John Doe', age: 28, city: 'New York' },
{ name: 'Jane Smith', age: 34, city: 'San Francisco' },
{ name: 'Sam Green', age: 45, city: 'Chicago' },
];
// 自定义列标题
const headers = ['Name', 'Age', 'City'];
// 数据按自定义顺序排序
const formattedData = data.map((item) => [item.name, item.age, item.city]);
// 将列标题与数据合并
const worksheetData = [headers, ...formattedData];
// 创建工作表
const worksheet = XLSX.utils.aoa_to_sheet(worksheetData);
// 创建工作簿并添加工作表
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
// 导出为 Blob
const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
const blob = new Blob([excelBuffer], { type: 'application/octet-stream' });
// 使用 FileSaver 保存文件
saveAs(blob, 'example_with_headers.xlsx');
};
return (
<div>
<button onClick={handleExport}>导出带自定义标题的 Excel</button>
</div>
);
};
export default ExportExcelWithHeaders;
四、设置列宽度
在 xlsx 中,可以通过设置工作表的 !cols 属性来自定义每一列的宽度。
import React from 'react';
import * as XLSX from 'xlsx';
import { saveAs } from 'file-saver';
const ExportExcelWithColumnWidths = () => {
... ...
// 创建工作表
const worksheet = XLSX.utils.aoa_to_sheet(worksheetData);
// 设置列宽
worksheet['!cols'] = [
{ wch: 15 }, // 第一列宽度:15字符
{ wch: 5 }, // 第二列宽度:5字符
{ wch: 20 }, // 第三列宽度:20字符
];
// 创建工作簿并添加工作表
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
... ...
};
... ...
};
export default ExportExcelWithColumnWidths;
- 列宽与内容长度匹配: 如果列内容长度可能变化,可以动态计算 wch:
const columnWidths = [
{ wch: Math.max(...data.map(item => item.name.length), 10) }, // 动态计算第一列宽度
{ wch: 5 },
{ wch: Math.max(...data.map(item => item.city.length), 15) },
];
worksheet['!cols'] = columnWidths;
- 注意事项
1.如果未设置 !cols,默认列宽会很窄,可能导致数据被截断。
2.wch 值可以设置为整数或浮点数,决定宽度的字符数。
3.列宽不会强制影响单元格内容换行。若希望内容换行,需要在单元格内容中加入换行符 \n 并配合样式(需借助 xlsx-style 或其他扩展库)。
五、样式优化
在 xlsx 中,默认的导出样式较为基础。如果需要对 Excel 文件进行样式优化(如字体、颜色、边框、对齐方式等),可以通过扩展库 xlsx-style 或 sheetjs-style 实现。
1、安装扩展库
这是一种扩展版的 xlsx,可以在导出的 Excel 中应用样式
npm install sheetjs-style
2、设置样式
import React from 'react';
import * as XLSX from 'sheetjs-style'; // 替代 xlsx 库
import { saveAs } from 'file-saver'; // 用于保存文件
const ExportExcelWithStyles = () => {
const handleExport = () => {
// 示例数据
const data = [
{ name: 'John Doe', age: 28, city: 'New York' },
{ name: 'Jane Smith', age: 34, city: 'San Francisco' },
{ name: 'Sam Green', age: 45, city: 'Chicago' },
];
// 自定义列标题
const headers = ['Name', 'Age', 'City'];
// 格式化数据
const formattedData = data.map((item) => [item.name, item.age, item.city]);
// 将标题与数据合并
const worksheetData = [headers, ...formattedData];
// 创建工作表
const worksheet = XLSX.utils.aoa_to_sheet(worksheetData);
// 设置样式
const headerStyle = {
font: { bold: true, color: { rgb: 'FFFFFF' } }, // 粗体,白色字体
fill: { fgColor: { rgb: '4F81BD' } }, // 蓝色背景
alignment: { horizontal: 'center', vertical: 'center' }, // 居中对齐
};
const bodyStyle = {
font: { color: { rgb: '000000' } }, // 黑色字体
alignment: { horizontal: 'left', vertical: 'center' }, // 左对齐
border: {
top: { style: 'thin', color: { rgb: 'CCCCCC' } },
bottom: { style: 'thin', color: { rgb: 'CCCCCC' } },
left: { style: 'thin', color: { rgb: 'CCCCCC' } },
right: { style: 'thin', color: { rgb: 'CCCCCC' } },
},
};
// 使用 XLSX.utils.encode_cell 获取单元格的地址,应用样式到标题行
headers.forEach((_, colIndex) => {
const cellAddress = XLSX.utils.encode_cell({ r: 0, c: colIndex });
//设置单元格样式
worksheet[cellAddress].s = headerStyle;
});
// 应用样式到数据行
formattedData.forEach((row, rowIndex) => {
row.forEach((_, colIndex) => {
const cellAddress = XLSX.utils.encode_cell({ r: rowIndex + 1, c: colIndex });
if (worksheet[cellAddress]) {
worksheet[cellAddress].s = bodyStyle;
}
});
});
// 设置列宽
worksheet['!cols'] = [
{ wch: 15 }, // 第一列宽度:15字符
{ wch: 5 }, // 第二列宽度:5字符
{ wch: 20 }, // 第三列宽度:20字符
];
// 创建工作簿并添加工作表
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, 'Styled Sheet');
// 导出为 Blob
const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
const blob = new Blob([excelBuffer], { type: 'application/octet-stream' });
// 使用 FileSaver 保存文件
saveAs(blob, 'styled_example.xlsx');
};
return (
<div>
<button onClick={handleExport}>导出带样式的 Excel</button>
</div>
);
};
export default ExportExcelWithStyles;
效果:
3、扩展样式功能
- 单元格合并: 使用 worksheet[‘!merges’] 属性:
worksheet['!merges'] = [
{ s: { r: 0, c: 0 }, e: { r: 0, c: 2 } }, // 合并第1行,第1~第3列
];
语法结构:
worksheet['!merges'] = [
{ s: { r: 起始行, c: 起始列 }, e: { r: 结束行, c: 结束列 } },
];
s
:表示合并范围的 起始单元格,包含两个属性:
r
:行号,从 0 开始(例如,第 1 行为 0)。c
:列号,从 0 开始(例如,A 列为 0,B 列为 1)。
e
:表示合并范围的 结束单元格,包含同样的 r 和 c 属性。
- 动态样式: 根据数据动态调整单元格样式,例如:
if (row.age > 30) {
worksheet[cellAddress].s = { fill: { fgColor: { rgb: 'FFC7CE' } } }; // 背景变红
}
- 自动筛选: 设置自动筛选功能(表头下的筛选按钮):
worksheet['!autofilter'] = { ref: 'A1:C1' }; // 设置 A1:C1 的自动筛选