当前位置: 首页 > article >正文

react中实现导出excel文件

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:表示合并范围的 起始单元格,包含两个属性:

  1. r:行号,从 0 开始(例如,第 1 行为 0)。
  2. 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 的自动筛选

http://www.kler.cn/a/448003.html

相关文章:

  • 探索 Seaborn Palette 的奥秘:为数据可视化增色添彩
  • leetcode之hot100---234回文链表(C++)
  • cad c# 二次开发 ——动态加载dll 文件制作(loada netloadx)
  • ChatGPT生成接口文档的方法与实践
  • 冯诺依曼架构与哈佛架构的对比与应用
  • 内置函数.
  • 【CSS in Depth 2 精译_088】第五部分:添加动效概述 + 第 15 章:CSS 过渡特效概述 + 15.1:状态间的由此及彼
  • 默契之舞 之 生产者消费者模式(RabbitMQ)
  • [react 3种方法] 获取ant组件ref用ts如何定义?
  • CSS系列(25)-- 滚动优化详解
  • [DASCTF 2024最后一战|寒夜破晓,冬至终章] 数论的气氛
  • rk3568之mpp开发笔记怎么实现mpp编码摄像头实时码流?
  • 换工作,如何退出微软账户???(删除注册表数据)
  • powerhsell 初认识
  • 252-8路SATAII 6U VPX高速存储模块
  • 一个类就创建Json反序列化所需的属性
  • golang,gowork工具
  • UI自动化概念+Web自动化测试框架
  • 第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ
  • CE之植物大战僵尸植物无冷却
  • 60.基于SSM的个人网站的设计与实现(项目 + 论文)
  • HarmonyOS NEXT 技术实践-基于意图框架服务实现智能分发
  • simulink离散传递函数得到差分方程并用C语言实现
  • 二叉树_堆
  • 实验二 组合逻辑电路部件实验
  • 青少年编程与数学 02-004 Go语言Web编程 07课题、WebSockets