楼主: vendettq2577
31 0

前端 Excel 导出完整指南 [推广有奖]

  • 0关注
  • 0粉丝

等待验证会员

学前班

80%

还不是VIP/贵宾

-

威望
0
论坛币
0 个
通用积分
0
学术水平
0 点
热心指数
0 点
信用等级
0 点
经验
30 点
帖子
2
精华
0
在线时间
0 小时
注册时间
2018-9-29
最后登录
2018-9-29

楼主
vendettq2577 发表于 2025-11-25 14:38:55 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币

在现代 Web 应用开发中,数据导出功能是用户常用的交互需求之一。本文将结合我在实现 Excel 文件导出过程中遇到的实际问题与应对策略,帮助开发者规避常见坑点,提升实现效率。

问题一:引入 xlsx 库时出现导入错误

错误现象:

import XLSX from 'xlsx'
// ? Error: export 'default' (imported as 'XLSX') was not found in 'xlsx'

原因分析:

xlsx

所使用的 SheetJS(即 xlsx 库)本质上是一个 CommonJS 模块,其设计并未包含默认导出(default export)。当使用 Webpack 或 Vite 等现代构建工具处理此类模块时,若尝试通过 default import 方式引入,系统因无法找到对应导出结构而抛出异常。

export default

解决方案:

采用命名空间导入方式替代默认导入:

import * as XLSX from 'xlsx'
// ? 正确:将所有导出内容作为一个对象导入

如此即可正常使用诸如

XLSX.utils

XLSX.read

XLSX.writeFile

等核心方法进行文件读写操作。

问题二:导出后样式未生效(如背景色、文字居中、加粗等)

错误现象:

生成的 Excel 文件中,所有单元格均无任何格式设置,包括字体加粗、对齐方式和填充颜色等。

原因分析:

官方版本的

xlsx

库仅支持基础的数据解析与写入功能,不提供对单元格样式的控制能力,例如颜色、边框、对齐或字体加粗等高级格式均无法通过该库直接实现。

解决方案:

推荐替换为社区持续维护并增强功能的分支库:

xlsx-js-style

该版本在保留原有 API 的基础上扩展了完整的样式支持。

import * as XLSX from 'xlsx-js-style'
// ? 支持样式的增强版本

安装命令如下:

npm install xlsx-js-style

完整实现:封装通用导出工具函数

基于上述两个关键问题的解决思路,我封装了一个可复用的前端导出工具,具备以下特性:

  • 支持自定义表头与字段映射关系
  • 全局单元格内容居中显示
  • 表头行自动应用背景色及加粗样式
  • 智能计算列宽,兼容中文与英文混合场景
  • 适用于多个不同表格页面的快速集成

核心代码实现:

import * as XLSX from "xlsx-js-style"
/**
 * 通用导出函数:支持自定义表头和对应字段
 * @param {Object} params
 * @param {Array} params.header  显示在第一行的表头名称数组,例如 ['姓名', '年龄']
 * @param {Array} params.key     对应数据的字段名数组,例如 ['name', 'age']
 * @param {Array} params.data    数据源(对象数组)
 * @param {String} params.filename 文件名
 * @param {Boolean} params.autoWidth 是否自动调整宽度
 * @param {String} params.headerBgColor 表头背景色,例如 'FFC000'(不带 # 号)
 */
export const exportCommonToExcel = ({ header, key, data, filename, autoWidth = true, headerBgColor = "FFC000" }) => {
  const wb = XLSX.utils.book_new()

  // 1. 过滤和映射数据:根据 key 数组提取数据,保证列顺序与 header 一致
  const arrData = data.map((item) => {
    return key.map((k) => item[k])
  })

  // 2. 将表头添加到第一行
  arrData.unshift(header)

  // 3. 生成 sheet
  const ws = XLSX.utils.aoa_to_sheet(arrData)

  const range = XLSX.utils.decode_range(ws["!ref"])
  for (let R = range.s.r; R <= range.e.r; ++R) {
    for (let C = range.s.c; C <= range.e.c; ++C) {
      const cellAddress = XLSX.utils.encode_cell({ r: R, c: C })
      if (!ws[cellAddress]) continue

      const cellStyle = {
        alignment: {
          horizontal: "center",
          vertical: "center",
        },
      }

      if (R === 0) {
        cellStyle.fill = {
          fgColor: { rgb: headerBgColor },
        }
        cellStyle.font = {
          bold: true,
          color: { rgb: "000000" },
        }
      }

      ws[cellAddress].s = cellStyle
    }
  }

  if (autoWidth) {
    auto_width(ws, arrData)
  }

  XLSX.utils.book_append_sheet(wb, ws, filename)
  XLSX.writeFile(wb, (filename || "export") + ".xlsx")
}

// 设置导出的宽度
function auto_width(ws, data) {
  /*set worksheet max width per col*/
  const colWidth = data.map((row) =>
    row.map((val) => {
      /*if null/undefined*/
      if (val == null) {
        return { wch: 10 }
      } else {
        // 防止数据过长导致需要滑动距离过长
        if (val.toString().length > 400) {
          return { wch: val.toString().length / 40 }
        } else {
          const isChinese = /[\u4e00-\u9fa5]/.test(val.toString())
          return {
            wch: isChinese
              ? val.toString().length * 2 + 2
              : val.toString().length + 2 < 10
                ? 10
                : val.toString().length + 2,
          }
        }
      }
    }),
  )
  /*start in the first row*/
  const result = colWidth[0]
  for (let i = 1; i < colWidth.length; i++) {
    for (let j = 0; j < colWidth[i].length; j++) {
      if (result[j]["wch"] < colWidth[i][j]["wch"]) {
        result[j]["wch"] = colWidth[i][j]["wch"]
      }
    }
  }
  ws["!cols"] = result
}

使用示例:

import { exportCommonToExcel } from '@/utils/excel-export'

// 原始数据 
const tableData = [ { id: 1, name: '张三', age: 28, department: '技术部', secret: 'xxx' }, { id: 2, name: '李四', age: 32, department: '产品部', secret: 'yyy' } ]

// 导出 
exportCommonToExcel({ 
header: ['员工ID', '姓名', '年龄', '部门'], // 自定义表头 
key: ['id', 'name', 'age', 'department'], // 指定字段(忽略 secret) 
data: tableData, 
filename: '员工信息表', 
headerBgColor: '4472C4' // 可选:自定义表头颜色(蓝色) 
})

进阶场景:实现“导出全部数据”功能

问题背景:

当前页面数据采用分页展示(例如每页显示 10 条记录),但用户点击“导出全部”按钮时,期望导出数据库中的全部 1000 条数据,而非仅限当前页。

可行方案如下:

方案一:前端统一拉取并生成(适用于数据量小于 1 万条)

利用已有的前端导出逻辑,先请求服务端获取完整数据集,再由浏览器本地完成文件生成:

import { exportCommonToExcel } from '@/utils/excel-export';

async function handleExportAll() {
  try {
    this.loading = true; // 开启 loading

    // 1. 准备查询参数,复用当前列表的搜索条件
    const params = {
      ...this.searchParams, 
      page: 1,
      pageSize: 99999 // 关键点:请求所有数据
    };

    // 2. 请求后端数据
    const res = await api.getUserList(params);
    const allData = res.data.list; // 拿到完整的列表

    // 3. 调用工具函数导出
    exportCommonToExcel({
      header: ['ID', '姓名', '手机号'],
      key:    ['id', 'name', 'phone'],
      data:   allData, // 这里传入的是刚刚请求到的【全部数据】
      filename: '所有用户数据'
    });

    this.$message.success('导出成功');

  } catch (error) {
    console.error(error);
    this.$message.error('导出失败');
  } finally {
    this.loading = false; // 关闭 loading
  }
}

优点:

  • 样式配置完全由前端掌控,灵活性高
  • 可复用现有导出工具和样式规则
  • 无需后端额外开发接口

缺点:

当数据量超过一定阈值(如 >1万条)时,可能导致页面卡顿甚至内存溢出。

方案二:后端生成并返回文件流(适用于大数据量,建议 >1 万条)

对于超大规模数据集,应交由服务端处理文件生成任务,并以流的形式返回给前端下载:

async function handleExportAll() {
  try {
    const res = await api.exportUsers(this.searchParams, {
      responseType: 'blob'  // 接收二进制流
    })

    // 创建下载链接
    const blob = new Blob([res.data], { 
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' 
    })
    const url = window.URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = url
    link.download = '用户数据.xlsx'
    link.click()
    window.URL.revokeObjectURL(url)
  } catch (error) {
    this.$message.error('导出失败')
  }
}

总结

本文围绕 Excel 导出功能的三大典型难题进行了深入剖析与实践验证:

  1. 导入报错问题:通过使用

    import * as XLSX from 'xlsx-js-style'

    语法进行命名空间导入,避免因缺少 default export 导致的构建失败。

  2. 样式失效问题:弃用原生

    xlsx

    改用支持样式的

    xlsx-js-style

    增强版库,实现丰富的单元格格式控制。

  3. 全量数据导出问题:根据数据规模选择合适策略——小数据量由前端统一获取并导出;大数据量则交由后端生成文件流,保障性能与稳定性。

最终达成一个兼具灵活性、可复用性与视觉表现力的 Excel 导出解决方案,适配多种业务场景下的实际需求。

二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:EXCEL xcel exce cel Application

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
jg-xs1
拉您进交流群
GMT+8, 2025-12-9 05:32