reactjs 在浏览器端实现导出 excel 功能

2025-06-27

本文是工作中用到的笔记📒,记录使用 reactjs 在浏览器端直接导出 excel 功能。

目录:

安装依赖包

$ yarn add exceljs file-saver

基础使用

import React from 'react'
import ExcelJS from 'exceljs'
import { saveAs } from 'file-saver'

const ExportExcel = () => {
  const exportToExcel = async () => {
    // 创建工作簿
    const workbook = new ExcelJS.Workbook()
    
    // 添加工作表
    const worksheet = workbook.addWorksheet('Sheet1')
    
    // 填充数据
    worksheet.addRow([ 'Name', 'Age', 'City' ])
    worksheet.addRow([ 'Alice', 25, 'New York' ])
    worksheet.addRow([ 'Bob', 30, 'London' ])
    
    // 生成 Excel 文件并下载
    const buffer = await workbook.xlsx.writeBuffer()
    const blob = new Blob([ buffer ], {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    })
    saveAs(blob, 'users.xlsx')
  }

  return (
    <div>
      <h2>Export Excel (Basic)</h2>
      <button onClick={exportToExcel}>Download Excel</button>
    </div>
  )
}

export default ExportExcel

合并单元格

import React from 'react'
import ExcelJS from 'exceljs'
import { saveAs } from 'file-saver'

const MergeCellsExample = () => {
  const exportWithMergedCells = async () => {
    // 创建工作簿
    const workbook = new ExcelJS.Workbook()
    
    // 添加工作表
    const worksheet = workbook.addWorksheet('Merged Cells')

    // 填充数据(合并单元格前)
    worksheet.addRow([ 'Region', 'Sales', 'Notes' ])
    worksheet.addRow([ 'East', 1000, 'Good performance' ])
    worksheet.addRow([ 'West', 800, 'Needs improvement' ])
    worksheet.addRow([ 'North', 1200, 'Excellent' ])
    worksheet.addRow([ 'South', 900, 'Stable' ])

    // 合并单元格(从 A1 到 C1)
    worksheet.mergeCells('A1:C1') // 合并第一行的 A、B、C 列
    worksheet.getCell('A1').value = 'Sales Report' // 设置合并后的单元格值
    worksheet.getCell('A1').font = { bold: true, size: 14 } // 设置样式

    // 合并其他单元格(从 B2 到 B3)
    worksheet.mergeCells('B2:B3') // 合并第二行和第三行的 B 列
    worksheet.getCell('B2').value = 'Total East & West' // 设置合并后的单元格值
    worksheet.getCell('B2').fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFF00' } } // 黄色背景

    // 合并单元格(从 C2 到 C4)
    worksheet.mergeCells('C2:C4') // 合并第二行到第四行的 C 列
    worksheet.getCell('C2').value = 'Regional Notes' // 设置合并后的单元格值
    worksheet.getCell('C2').font = { italic: true } // 斜体

    // 生成 Excel 文件并下载
    const buffer = await workbook.xlsx.writeBuffer()
    const blob = new Blob([ buffer ], {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    })
    saveAs(blob, 'merged_cells_example.xlsx')
  }

  return (
    <div>
      <h2>ExcelJS 合并单元格示例</h2>
      <button onClick={exportWithMergedCells}>导出 Excel(带合并单元格)</button>
    </div>
  )
}

export default MergeCellsExample

设置单元格字体颜色

import React from 'react'
import ExcelJS from 'exceljs'
import { saveAs } from 'file-saver'

const ExcelFontColorExample = () => {
  const exportWithFontColor = async () => {
    // 创建工作簿
    const workbook = new ExcelJS.Workbook()
    
    // 添加工作表
    const worksheet = workbook.addWorksheet('Font Color Example')

    // 填充数据
    worksheet.addRow([ 'Apple', 10, 'In Stock' ])
    worksheet.addRow([ 'Banana', 5, 'Low Stock' ])
    worksheet.addRow([ 'Orange', 8, 'Out of Stock' ])

    // 设置字体颜色(使用 ARGB 格式)
    // 第一行数据(Apple)
    worksheet.getCell('A1').font = { color: { argb: 'FF0000' } } // 红色
    worksheet.getCell('B1').font = { color: { argb: '00FF00' } } // 绿色
    worksheet.getCell('C1').font = { color: { argb: '0000FF' } } // 蓝色

    // 第二行数据(Banana)
    worksheet.getCell('A2').font = { color: { argb: 'FFA500' } } // 橙色
    worksheet.getCell('B2').font = { color: { argb: '800080' } } // 紫色
    worksheet.getCell('C2').font = { color: { argb: 'FF00FF' } } // 品红

    // 第三行数据(Orange)
    worksheet.getCell('A3').font = { color: { argb: '000000' } } // 黑色
    worksheet.getCell('B3').font = { color: { argb: '808080' } } // 灰色
    worksheet.getCell('C3').font = { color: { argb: 'A52A2A' } } // 棕色

    // 生成 Excel 文件并下载
    const buffer = await workbook.xlsx.writeBuffer()
    const blob = new Blob([ buffer ], {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    })
    saveAs(blob, 'font_color_example.xlsx')
  }

  return (
    <div>
      <h2>ExcelJS 设置字体颜色示例</h2>
      <button onClick={exportWithFontColor}>导出带字体颜色的 Excel</button>
    </div>
  )
}

export default ExcelFontColorExample

设置单元格字体加粗

import React from 'react'
import ExcelJS from 'exceljs'
import { saveAs } from 'file-saver'

const ExcelBoldFontExample = () => {
  const exportWithBoldFont = async () => {
    // 创建工作簿
    const workbook = new ExcelJS.Workbook()
    
    // 添加工作表
    const worksheet = workbook.addWorksheet('Bold Font Example')

    // 填充数据
    worksheet.addRow([ 'Product', 'Price', 'Status' ])
    worksheet.addRow([ 'Apple', 10, 'In Stock' ])
    worksheet.addRow([ 'Banana', 5, 'Low Stock' ])
    worksheet.addRow([ 'Orange', 8, 'Out of Stock' ])

    // 设置字体加粗样式
    // 方法1:设置整行加粗(表头)
    worksheet.getRow(1).font = { bold: true }

    // 方法2:设置特定单元格加粗
    worksheet.getCell('A2').font = { bold: true } // Apple 产品名称加粗
    worksheet.getCell('B3').font = { bold: true } // Banana 价格加粗
    worksheet.getCell('C4').font = { bold: true } // Orange 状态加粗

    // 方法3:设置整列加粗(价格列)
    worksheet.getColumn(2).font = { bold: true }

    // 生成 Excel 文件并下载
    const buffer = await workbook.xlsx.writeBuffer()
    const blob = new Blob([ buffer ], {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    })
    saveAs(blob, 'bold_font_example.xlsx')
  }

  return (
    <div>
      <h2>ExcelJS 设置字体加粗示例</h2>
      <button onClick={exportWithBoldFont}>导出带加粗字体的 Excel</button>
    </div>
  )
}

export default ExcelBoldFontExample

设置单元格字体对齐方式

import React from 'react'
import ExcelJS from 'exceljs'
import { saveAs } from 'file-saver'

const ExcelAlignmentExample = () => {
  const exportWithAlignment = async () => {
    // 创建工作簿
    const workbook = new ExcelJS.Workbook()
    
    // 添加工作表
    const worksheet = workbook.addWorksheet('Alignment Example')

    // 填充数据
    worksheet.addRow([ 'Product', 'Price', 'Stock' ])
    worksheet.addRow([ 'Apple', 10, 100 ])
    worksheet.addRow([ 'Banana', 5, 200 ])
    worksheet.addRow([ 'Orange', 8, 150 ])

    // 设置字体对齐方式
    // 方法1:设置整行对齐(表头)
    worksheet.getRow(1).alignment = { 
      horizontal: 'center', // 水平居中
      vertical: 'middle',   // 垂直居中
    }

    // 方法2:设置特定单元格对齐
    worksheet.getCell('A2').alignment = { horizontal: 'left' } // Product 名称左对齐
    worksheet.getCell('B2').alignment = { horizontal: 'right' } // Price 右对齐
    worksheet.getCell('C2').alignment = { horizontal: 'center' } // Stock 居中对齐

    // 方法3:设置整列对齐(价格列右对齐)
    worksheet.getColumn(2).alignment = { horizontal: 'right' }

    // 生成 Excel 文件并下载
    const buffer = await workbook.xlsx.writeBuffer()
    const blob = new Blob([ buffer ], {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    })
    saveAs(blob, 'alignment_example.xlsx')
  }

  return (
    <div>
      <h2>ExcelJS 设置字体对齐方式示例</h2>
      <button onClick={exportWithAlignment}>导出带对齐方式的 Excel</button>
    </div>
  )
}

export default ExcelAlignmentExample

设置单元格数字格式化

比如 10000 在单元格中显示 10,000
比如 0.1 在单元格中显示 10%

import React from 'react'
import ExcelJS from 'exceljs'
import { saveAs } from 'file-saver'

const ExcelFormattingExample = () => {
  const exportFormattedExcel = async () => {
    // 创建工作簿
    const workbook = new ExcelJS.Workbook()
    
    // 添加工作表
    const worksheet = workbook.addWorksheet('Formatted Numbers')

    // 定义自定义数字格式
    // 这里定义了几种常见的数字格式
    const numberFormats = {
      INTEGER: '0', // 整数,例如 10000 显示为 10000
      COMMA_SEPARATED: '0,0', // 带千位分隔符,例如 10000 显示为 10,000
      DECIMAL_TWO_PLACES: '0.00', // 两位小数,例如 10000.5 显示为 10000.50
      CURRENCY: '$#,##0.00', // 货币格式,例如 10000 显示为 $10,000.00
      PERCENTAGE: '0%', // 百分比,例如 0.1 显示为 10%
    }

    // 填充数据
    worksheet.addRow([ 'Item', 'Quantity', 'Price', 'Discount' ])
    worksheet.addRow([ 'Apples', 10000, 5.5, 0.1 ])
    worksheet.addRow([ 'Bananas', 5000, 3.2, 0.05 ])
    worksheet.addRow([ 'Oranges', 7500, 4.0, 0.15 ])

    // 应用自定义数字格式
    worksheet.getColumn(2).numFmt = numberFormats.COMMA_SEPARATED // Quantity 列,带千位分隔符
    worksheet.getColumn(3).numFmt = numberFormats.CURRENCY // Price 列,货币格式
    worksheet.getColumn(4).numFmt = numberFormats.PERCENTAGE // Discount 列,百分比

    // 生成 Excel 文件并下载
    const buffer = await workbook.xlsx.writeBuffer()
    const blob = new Blob([ buffer ], {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    })
    saveAs(blob, 'formatted_numbers.xlsx')
  }

  return (
    <div>
      <h2>ExcelJS 数字格式化示例</h2>
      <button onClick={exportFormattedExcel}>导出带格式化的 Excel</button>
    </div>
  )
}

export default ExcelFormattingExample

设置单元格背景颜色

import React from 'react'
import ExcelJS from 'exceljs'
import { saveAs } from 'file-saver'

const ExcelBackgroundColorExample = () => {
  const exportWithBackgroundColor = async () => {
    // 创建工作簿
    const workbook = new ExcelJS.Workbook()
    
    // 添加工作表
    const worksheet = workbook.addWorksheet('Background Color Example')

    // 填充数据
    worksheet.addRow([ 'ID', '姓名', '年龄', '销售额', '状态' ])
    worksheet.addRow([ 1, '张三', 28, 50000, '已完成' ])
    worksheet.addRow([ 2, '李四', 34, 75000, '进行中' ])
    worksheet.addRow([ 3, '王五', 45, 60000, '已完成' ])
    worksheet.addRow([ 4, '赵六', 23, 40000, '未开始' ])
    worksheet.addRow([ 5, '孙七', 30, 55000, '进行中' ])

    // 设置单元格背景颜色

    // 方法1:设置单个单元格背景颜色
    worksheet.getCell('A1').fill = {
      type: 'pattern',
      pattern: 'solid',
      fgColor: { argb: 'FF999999' }, // 灰色背景
    }

    // 方法2:设置整行背景颜色(例如,表头行)
    worksheet.getRow(1).fill = {
      type: 'pattern',
      pattern: 'solid',
      fgColor: { argb: 'FF4472C4' }, // 蓝色背景
    }

    // 方法3:设置整列背景颜色(例如,销售额列)
    worksheet.getColumn(4).fill = {
      type: 'pattern',
      pattern: 'solid',
      fgColor: { argb: 'FFE2FFE2' }, // 浅绿色背景
    }

    // 方法4:根据条件设置背景颜色
    worksheet.eachRow({ includeEmpty: true }, (row, rowNumber) => {
      if (rowNumber > 1) { // 跳过表头
        const status = row.getCell('E').value
        if (status === '已完成') {
          row.fill = {
            type: 'pattern',
            pattern: 'solid',
            fgColor: { argb: 'FF00FF00' }, // 绿色背景
          }
        } else if (status === '进行中') {
          row.fill = {
            type: 'pattern',
            pattern: 'solid',
            fgColor: { argb: 'FFFF9900' }, // 橙色背景
          }
        } else if (status === '未开始') {
          row.fill = {
            type: 'pattern',
            pattern: 'solid',
            fgColor: { argb: 'FFFF0000' }, // 红色背景
          }
        }
      }
    })

    // 生成 Excel 文件并下载
    const buffer = await workbook.xlsx.writeBuffer()
    const blob = new Blob([ buffer ], {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    })
    saveAs(blob, 'background_color_example.xlsx')
  }

  return (
    <div>
      <h2>ExcelJS 设置单元格背景颜色示例</h2>
      <button onClick={exportWithBackgroundColor}>导出带背景颜色的 Excel</button>
    </div>
  )
}

export default ExcelBackgroundColorExample

设置单元格边框

import React from 'react'
import ExcelJS from 'exceljs'
import { saveAs } from 'file-saver'

const ExcelBordersExample = () => {
  const exportWithBorders = async () => {
    // 创建工作簿
    const workbook = new ExcelJS.Workbook()
    
    // 添加工作表
    const worksheet = workbook.addWorksheet('Borders Example')

    // 填充数据
    worksheet.addRow([ 'ID', '姓名', '年龄', '销售额', '状态' ])
    worksheet.addRow([ 1, '张三', 28, 50000, '已完成' ])
    worksheet.addRow([ 2, '李四', 34, 75000, '进行中' ])
    worksheet.addRow([ 3, '王五', 45, 60000, '已完成' ])
    worksheet.addRow([ 4, '赵六', 23, 40000, '未开始' ])
    worksheet.addRow([ 5, '孙七', 30, 55000, '进行中' ])

    // 设置单元格边框

    // 方法1:设置单个单元格边框
    const cellA1 = worksheet.getCell('A1')
    cellA1.border = {
      top: { style: 'thin', color: { argb: 'FF000000' } },
      left: { style: 'thin', color: { argb: 'FF000000' } },
      bottom: { style: 'thin', color: { argb: 'FF000000' } },
      right: { style: 'thin', color: { argb: 'FF000000' } },
    }

    // 方法2:设置整行边框
    const headerRow = worksheet.getRow(1)
    headerRow.border = {
      top: { style: 'double', color: { argb: 'FF0000FF' } },
      left: { style: 'thin', color: { argb: 'FF000000' } },
      bottom: { style: 'double', color: { argb: 'FF0000FF' } },
      right: { style: 'thin', color: { argb: 'FF000000' } },
    }

    // 方法3:设置整列边框
    worksheet.getColumn(4).border = {
      top: { style: 'dashed', color: { argb: 'FFFF0000' } },
      left: { style: 'thin', color: { argb: 'FF000000' } },
      bottom: { style: 'dashed', color: { argb: 'FFFF0000' } },
      right: { style: 'thin', color: { argb: 'FF000000' } },
    }

    // 方法4:根据条件设置边框
    worksheet.eachRow({ includeEmpty: true }, (row, rowNumber) => {
      if (rowNumber > 1) { // 跳过表头
        const status = row.getCell('E').value
        if (status === '已完成') {
          row.border = {
            top: { style: 'medium', color: { argb: 'FF00FF00' } },
            left: { style: 'thin', color: { argb: 'FF000000' } },
            bottom: { style: 'medium', color: { argb: 'FF00FF00' } },
            right: { style: 'thin', color: { argb: 'FF000000' } },
          }
        } else if (status === '进行中') {
          row.border = {
            top: { style: 'dotted', color: { argb: 'FFFFFF00' } },
            left: { style: 'thin', color: { argb: 'FF000000' } },
            bottom: { style: 'dotted', color: { argb: 'FFFFFF00' } },
            right: { style: 'thin', color: { argb: 'FF000000' } },
          }
        } else if (status === '未开始') {
          row.border = {
            top: { style: 'hair', color: { argb: 'FFFF0000' } },
            left: { style: 'thin', color: { argb: 'FF000000' } },
            bottom: { style: 'hair', color: { argb: 'FFFF0000' } },
            right: { style: 'thin', color: { argb: 'FF000000' } },
          }
        }
      }
    })

    // 生成 Excel 文件并下载
    const buffer = await workbook.xlsx.writeBuffer()
    const blob = new Blob([ buffer ], {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    })
    saveAs(blob, 'borders_example.xlsx')
  }

  return (
    <div>
      <h2>ExcelJS 设置单元格边框示例</h2>
      <button onClick={exportWithBorders}>导出带边框的 Excel</button>
    </div>
  )
}

export default ExcelBordersExample

设置单元格宽度和高度

import React from 'react'
import ExcelJS from 'exceljs'
import { saveAs } from 'file-saver'

const ExcelDimensionsExample = () => {
  const exportWithDimensions = async () => {
    // 创建工作簿
    const workbook = new ExcelJS.Workbook()
    
    // 添加工作表
    const worksheet = workbook.addWorksheet('Dimensions Example')

    // 填充数据
    worksheet.addRow([ 'ID', '姓名', '年龄', '销售额', '状态' ])
    worksheet.addRow([ 1, '张三', 28, 50000, '已完成' ])
    worksheet.addRow([ 2, '李四', 34, 75000, '进行中' ])
    worksheet.addRow([ 3, '王五', 45, 60000, '已完成' ])
    worksheet.addRow([ 4, '赵六', 23, 40000, '未开始' ])
    worksheet.addRow([ 5, '孙七', 30, 55000, '进行中' ])

    // 设置列宽
    worksheet.columns = [
      { key: 'id', header: 'ID', width: 8 },
      { key: 'name', header: '姓名', width: 12 },
      { key: 'age', header: '年龄', width: 10 },
      { key: 'sales', header: '销售额', width: 15 },
      { key: 'status', header: '状态', width: 15 },
    ]

    // 设置行高
    worksheet.getRow(1).height = 30 // 设置表头行高为 30
    worksheet.getRow(2).height = 25 // 设置第二行行高为 25
    worksheet.getRow(3).height = 25
    worksheet.getRow(4).height = 25
    worksheet.getRow(5).height = 25

    // 生成 Excel 文件并下载
    const buffer = await workbook.xlsx.writeBuffer()
    const blob = new Blob([ buffer ], {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    })
    saveAs(blob, 'dimensions_example.xlsx')
  }

  return (
    <div>
      <h2>ExcelJS 设置单元格宽度和高度示例</h2>
      <button onClick={exportWithDimensions}>导出带尺寸的 Excel</button>
    </div>
  )
}

export default ExcelDimensionsExample

插入图片

import React from 'react'
import ExcelJS from 'exceljs'
import { saveAs } from 'file-saver'

const ExcelImageExample = () => {
  const exportWithImage = async () => {
    // 创建工作簿
    const workbook = new ExcelJS.Workbook()
    
    // 添加工作表
    const worksheet = workbook.addWorksheet('Image Example')

    // 填充数据(可选)
    worksheet.addRow([ '产品', '描述' ])
    worksheet.addRow([ '苹果', '新鲜的红色苹果' ])
    worksheet.addRow([ '香蕉', '黄色的香蕉' ])
    worksheet.addRow([ '橙子', '多汁的橙子' ])

    // 定义图片 URL
    const imageUrl = 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSGqDZK9waX9I8CnvoI0GhVUF6Q3i6Z0v7Rmg&s'

    try {
      // 获取图片数据(Buffer)
      const response = await fetch(imageUrl)
      if (!response.ok) {
        throw new Error(`无法加载图片: ${response.statusText}`)
      }
      const imageBuffer = await response.arrayBuffer()

      // 添加图片到工作簿
      const imageId = workbook.addImage({
        buffer: imageBuffer,
        extension: 'jpeg', // 根据实际图片类型调整(如 png, jpg 等)
      })

      // 插入图片到指定单元格(例如 A5)
      // 参数:图片ID, 插入位置('A5'),宽度, 高度
      worksheet.addImage(imageId, {
        tl: { col: 0, row: 4 }, // A5 单元格(列从0开始计数)
        ext: { width: 200, height: 200 }, // 图片尺寸(像素)
      })

    } catch (error) {
      console.error('插入图片失败:', error)
      alert('无法插入图片,请检查图片 URL 是否有效。')
      return
    }

    // 生成 Excel 文件并下载
    const buffer = await workbook.xlsx.writeBuffer()
    const blob = new Blob([ buffer ], {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    })
    saveAs(blob, 'image_example.xlsx')
  }

  return (
    <div>
      <h2>将图片插入到 Excel 示例</h2>
      <button onClick={exportWithImage}>导出带图片的 Excel</button>
    </div>
  )
}

export default ExcelImageExample

返回首页

本文总阅读量  次
皖ICP备17026209号-3
总访问量: 
总访客量: