纯JS 导出 Excel 工具

适用文件:excel.js

适用场景:后台管理系统、列表导出、统计报表导出、后端 Blob 文件下载


1. 能力概览

excel.js 提供 4 类核心能力:

  1. exportExcelByTableHtml:你已经有 <table> 字符串时直接导出
  2. exportExcelByTableElement:页面上已有 table DOM 时直接导出
  3. exportExcelByColumns:传列配置 + 数据,自动拼 table 并导出
  4. exportByAxiosResponse:后端返回 blob 时一键下载

补充基础能力:

  • downloadByDataUri:下载文本内容
  • downloadByBlob:下载 Blob 内容
  • parseFileNameFromDisposition:从响应头解析文件名

2. 安装/接入方式

2.1 本项目内使用

js 复制代码
import {
  exportExcelByTableHtml,
  exportExcelByTableElement,
  exportExcelByColumns,
  exportByAxiosResponse
} from '@/utils/excel'

2.2 复制到任意前端项目

src/utils/excel.js 复制到你的项目中(例如 src/utils/excel.js),然后按实际路径引入即可:

js 复制代码
import { exportExcelByColumns } from './utils/excel'

3. 使用前说明(重要)

  1. 当前方案是 HTML Table 兼容 Excel 的 .xls 导出
  2. 对中文、常规文本、简单样式兼容性好
  3. 如果你需要复杂能力(多 sheet、公式、冻结窗格、复杂样式),建议改用 SheetJS(xlsx
  4. 本工具依赖浏览器环境(window/document),不能在纯 Node 环境直接执行下载

4. 详细示例

4.1 场景A:你已经有 tableHtml 字符串

js 复制代码
import { exportExcelByTableHtml } from '@/utils/excel'

function handleExport() {
  let row = '<table border="1" cellspacing="0" cellpadding="4">'
  row += '<tr><td>序号</td><td>姓名</td><td>分数</td></tr>'
  row += '<tr><td>1</td><td>张三</td><td>95</td></tr>'
  row += '<tr><td>2</td><td>李四</td><td>88</td></tr>'
  row += '</table>'

  exportExcelByTableHtml({
    tableHtml: row,
    fileName: '成绩统计',
    sheetName: '成绩',
    ext: '.xls'
  })
}

4.2 场景B:直接导出页面中已有 table

适用于页面有原生 <table> 或第三方渲染后真实 table DOM。

js 复制代码
import { exportExcelByTableElement } from '@/utils/excel'

function handleExportByDom() {
  exportExcelByTableElement({
    table: '#report-table', // 也可以传 document.querySelector(...) 得到的元素
    fileName: '报表明细',
    sheetName: '明细'
  })
}

模板示例:

html 复制代码
<table id="report-table">
  <tr>
    <td>地区</td>
    <td>参赛队数</td>
  </tr>
  <tr>
    <td>南宁</td>
    <td>12</td>
  </tr>
</table>

4.3 场景C:按列配置导出(推荐)

最通用,建议新页面都用这一种。

js 复制代码
import { exportExcelByColumns } from '@/utils/excel'

function exportTeamSummary(list) {
  exportExcelByColumns({
    title: '参赛队数汇总',
    fileName: '参赛队数汇总',
    sheetName: '汇总',
    emptyText: '--',
    columns: [
      { label: '序号', key: 'index', headerStyle: 'text-align:center;font-weight:bold;' },
      { label: '赛道名称', key: 'proj_name' },
      { label: '承办校', key: 'place_name' },
      { label: '队伍数量', key: 'num' },
      {
        label: '参赛人数',
        key: 'people',
        formatter: (row) => Number(row.people || 0)
      }
    ],
    data: list.map((item, i) => ({
      index: i + 1,
      proj_name: item.proj_name,
      place_name: item.place_name,
      num: item.num,
      people: item.people
    }))
  })
}

formatter 进阶示例

js 复制代码
{
  label: '状态',
  key: 'status',
  formatter: (row) => {
    const map = { 0: '待审核', 1: '通过', 2: '驳回' }
    return map[row.status] || '未知'
  }
}

4.4 场景D:后端 Blob 导出

适用于接口返回文件流,比如 responseType: 'blob'

js 复制代码
import axios from 'axios'
import { exportByAxiosResponse } from '@/utils/excel'

function exportFromApi(params) {
  axios({
    method: 'get',
    url: '/api/report/export',
    params,
    responseType: 'blob'
  }).then((res) => {
    // 优先取响应头文件名;没有时使用兜底名
    exportByAxiosResponse(res, '报表导出.xlsx')
  })
}

4.5 场景E:Vue2 页面完整接入示例

vue 复制代码
<script>
import { exportExcelByColumns } from '@/utils/excel'
import { match_proj_people } from '@/api/xxx'

export default {
  methods: {
    async handleDown() {
      const res = await match_proj_people(this.form)
      const list = (res && res.data && res.data.list) || []

      exportExcelByColumns({
        title: '参赛队数汇总',
        fileName: '参赛队数汇总',
        sheetName: 'Sheet1',
        columns: [
          { label: '序号', key: 'index' },
          { label: '赛道名称', key: 'proj_name' },
          { label: '承办校', key: 'place_name' },
          { label: '参赛队伍数量', key: 'num' },
          { label: '参赛人数', key: 'people', formatter: r => Number(r.people || 0) }
        ],
        data: list.map((item, i) => ({ index: i + 1, ...item }))
      })
    }
  }
}
</script>

5. API 速查

exportExcelByTableHtml(options)

  • tableHtml: string 表格 html
  • fileName?: string 文件名,默认 导出数据
  • sheetName?: string sheet 名,默认 Sheet1
  • ext?: string 后缀,默认 .xls

exportExcelByTableElement(options)

  • table: HTMLElement | string DOM 或选择器(必填)
  • 其他参数同上

exportExcelByColumns(options)

  • title?: string 标题行
  • columns: Array<Column> 列配置(建议必填)
  • data: any[] 行数据(建议必填)
  • emptyText?: string 空值填充值
  • tableAttrs?: string table 标签属性
  • fileName/sheetName/ext 同上

Column 结构:

  • label: string
  • key: string
  • formatter?: (row, rowIndex, col, colIndex) => any
  • headerStyle?: string
  • cellStyle?: string

exportByAxiosResponse(response, fallbackFileName?)

  • response: axios 响应对象(responseType: 'blob'
  • fallbackFileName: 响应头无文件名时的兜底名

6. 常见问题

6.1 为什么导出的不是严格 xlsx?

因为当前实现是 HTML Table 兼容模式(.xls),优点是简单、零依赖;缺点是高级能力有限。

6.2 中文文件名乱码怎么办?

优先让后端在 content-disposition 返回 UTF-8 文件名;前端已做 decodeURIComponent 兼容处理。

6.3 导出值中含有 HTML 标签怎么办?

工具默认做了 HTML 转义,避免内容串结构。若你确实要导出富文本,建议先在业务层做可控转换。

6.4 可以导出大数据量吗?

可以,但前端拼接超大 table 会占内存。大数据导出建议走后端生成文件流,再用 exportByAxiosResponse 下载。


相关推荐
To_OC5 小时前
LC 49 字母异位词分组:想到哈希表很简单,选对 key 才是精髓
javascript·算法·leetcode
kyriewen7 小时前
用了半年 Claude Code 后,我尝试关掉它写了一周代码——结果比想象中严重
前端·javascript·ai编程
山河木马9 小时前
矩阵专题0-webGL中的矩阵
javascript·webgl·计算机图形学
Asize9 小时前
多模态生图:从 Vite 工程化到前端调用 Qwen Image
javascript·人工智能·后端
陳陈陳9 小时前
从Token到Embedding:一篇文章搞懂大模型的「文字数学变形记」
前端·javascript·ai编程
用户9385156350710 小时前
从 O(n²) 到 O(nlogn):一文读懂快速排序的“快”与“妙”
javascript·算法
橘子星10 小时前
LLM 无状态架构实践:从原理到代码落地
前端·javascript·人工智能
To_OC11 小时前
手写快排次次翻车?别死背快排模板了,这才是面试官想听的底层逻辑
javascript·算法·排序算法
风止何安啊12 小时前
网课倍速痛点解决:一套前端代码实现自由控速播放器
前端·javascript·node.js
光影少年13 小时前
原生DOM操作在React 中的注意事项
前端·javascript·react.js