在日常开发中,表格数据导出Excel是高频需求,多数场景下依赖后端接口返回二进制文件实现下载。但当无后端接口支持时,前端也可通过纯前端方案完成导出,以下是两种实用方案的详细实现与对比。
方案1:纯前端Blob+HTML拼接方案(兼容所有浏览器)
该方案通过拼接HTML
字符串模拟Excel
结构,转换为Blob
对象后触发下载,是早期无框架时代的经典实现方式,兼容性覆盖所有主流浏览器。
核心原理
- 拼接包含
Excel
格式声明的HTML字符串(引入微软Office
相关命名空间,确保Excel
能正确解析); 2. 将HTML字符串转为Blob
对象,通过URL.createObjectURL
生成临时内存地址; 3. 动态创建a
标签指向该地址,触发点击事件完成下载,最后清理临时资源避免内存泄漏。
完整代码
js
/**
* 纯前端Blob方案导出Table为Excel
* @param {string} tableID - 页面中表格的ID
* @param {string} filename - 导出文件的名称(默认export)
*/
function exportTableToExcel(tableID, filename = '') {
// 1. 获取表格DOM元素,校验合法性
const table = document.getElementById(tableID);
if (!table) {
console.error('导出失败:未找到ID为「' + tableID + '」的表格元素');
return;
}
// 2. 拼接HTML字符串(包含Excel解析所需的命名空间和配置)
let html = `
<html xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns="http://www.w3.org/TR/REC-html40">
<head>
<!-- 针对Excel的兼容性配置:显示网格线 -->
<!--[if gte mso 9]>
<xml>
<x:ExcelWorkbook>
<x:ExcelWorksheets>
<x:ExcelWorksheet>
<x:Name>${filename || 'Sheet1'}</x:Name>
<x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions>
</x:ExcelWorksheet>
</x:ExcelWorksheets>
</x:ExcelWorkbook>
</xml>
<![endif]-->
<meta charset="UTF-8">
</head>
<body>${table.outerHTML}</body>
</html>
`;
// 3. 创建Blob对象(指定Excel文件类型)
const blob = new Blob([html], { type: 'application/vnd.ms-excel' });
// 4. 动态创建下载链接并触发下载
const link = document.createElement('a');
link.href = URL.createObjectURL(blob); // 生成Blob临时URL
link.download = `${filename || 'export'}.xls`; // 定义下载文件名
document.body.appendChild(link); // 挂载到DOM(部分浏览器需显式挂载才能触发点击)
link.click(); // 触发下载
// 5. 清理临时资源(避免内存泄漏)
setTimeout(() => {
document.body.removeChild(link); // 移除临时a标签
URL.revokeObjectURL(link.href); // 释放Blob URL内存
}, 100);
}
优缺点分析
优点
:无依赖,无需安装任何包;兼容所有浏览器(包括IE)。缺点
:通过字符串拼接HTML,代码冗余且易出错;仅支持导出 .xls 格式(不支持 .xlsx );复杂表格(如合并单元格)可能解析异常。
方案2:基于XLSX库的优雅方案(推荐)
借助开源库 xlsx (SheetJS社区版)处理表格数据与Excel格式转换,搭配 file-saver 优化下载逻辑,代码可复用性高,支持复杂表格与 .xlsx 格式。
前置准备:安装依赖
js
npm install xlsx file-saver --save
xlsx
:SheetJS社区版核心库,负责表格数据与Excel格式的转换;file-saver
:简化Blob对象下载逻辑,解决跨浏览器兼容性问题。
1. 基础版:直接导出页面Table
适用于需导出页面已渲染好的Table场景,直接从DOM解析表格数据。
js
import * as XLSX from 'xlsx';
import { saveAs } from 'file-saver';
/**
* 基于XLSX导出页面Table为Excel
* @param {string} tableId - 页面表格ID
* @param {string} fileName - 导出文件名称(默认export)
* @param {string} sheetName - Excel工作表名称(默认Sheet1)
*/
const exportExcelFromTable = (tableId, fileName = 'export', sheetName = 'Sheet1') => {
try {
// 1. 获取表格DOM并转为Excel工作表(worksheet)
const table = document.getElementById(tableId);
if (!table) {
console.error('导出失败:未找到指定Table元素');
return;
}
const worksheet = XLSX.utils.table_to_sheet(table); // DOM → 工作表
// 2. 创建Excel工作簿(workbook)并添加工作表
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, sheetName); // 工作簿添加工作表
// 3. 生成Excel文件流并下载
const excelBuffer = XLSX.write(workbook, {
bookType: 'xlsx', // 导出格式(xlsx/xls/csv等)
type: 'array' // 输出类型为ArrayBuffer
});
const blob = new Blob([excelBuffer], { type: 'application/octet-stream' });
saveAs(blob, `${fileName}.xlsx`); // 触发下载
} catch (error) {
console.error('Excel导出失败:', error);
}
};
2. 进阶版:React导出组件(可复用)
适用于React项目,支持通过 data 和 columns 配置导出(无需依赖页面DOM),可直接集成到业务组件中。
js
import React from 'react';
import * as XLSX from 'xlsx';
import { saveAs } from 'file-saver';
/**
* React Table导出Excel组件
* @param {Array} data - 表格数据源(数组对象,如[{id:1, name:'xxx'}, ...])
* @param {Array} columns - 表格列配置(如[{title:'ID', dataIndex:'id'}, ...])
* @param {string} fileName - 导出文件名(默认export)
* @param {string} sheetName - 工作表名称(默认Sheet1)
* @param {string} buttonLabel - 导出按钮文本(默认"导出Excel")
* @param {Object} buttonStyle - 按钮自定义样式
* @param {ReactNode} children - 自定义触发元素(如按钮、图标)
*/
const TableExporter = ({
data = [],
columns = [],
fileName = 'export',
sheetName = 'Sheet1',
buttonLabel = '导出Excel',
buttonStyle = {},
children
}) => {
const exportToExcel = () => {
try {
// 1. 处理数据:根据columns匹配表头与数据
const formattedData = data.map(row => {
const rowData = {};
columns.forEach(col => {
rowData[col.title] = row[col.dataIndex]; // 表头→数据映射
});
return rowData;
});
// 2. 创建工作表与工作簿
const worksheet = XLSX.utils.json_to_sheet(formattedData); // JSON → 工作表
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);
// 3. 生成Excel文件并下载
const excelBuffer = XLSX.write(workbook, {
bookType: 'xlsx',
type: 'array'
});
const blob = new Blob([excelBuffer], { type: 'application/octet-stream' });
saveAs(blob, `${fileName}.xlsx`);
} catch (error) {
console.error('Excel导出失败:', error);
}
};
// 支持自定义触发元素(如传入按钮、图标),无children则使用默认按钮
return children ? (
React.cloneElement(children, { onClick: exportToExcel })
) : (
<button
onClick={exportToExcel}
style={{
padding: '8px 16px',
backgroundColor: '#1890ff',
color: '#fff',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
...buttonStyle // 支持自定义样式覆盖
}}
>
{buttonLabel}
</button>
);
};
export default TableExporter;
组件使用示例
js
// 在业务组件中使用
import TableExporter from './TableExporter';
const BusinessComponent = () => {
// 表格数据源
const tableData = [
{ id: 1, name: '张三', age: 25 },
{ id: 2, name: '李四', age: 30 }
];
// 列配置
const tableColumns = [
{ title: '用户ID', dataIndex: 'id' },
{ title: '用户名', dataIndex: 'name' },
{ title: '年龄', dataIndex: 'age' }
];
return (
<div>
{/* 使用默认按钮 */}
<TableExporter
data={tableData}
columns={tableColumns}
fileName="用户列表"
/>
{/* 自定义触发元素(如Icon按钮) */}
<TableExporter
data={tableData}
columns={tableColumns}
fileName="用户列表"
>
<button style={{ marginLeft: '10px' }}>
<<i className="icon-export"></</i> 导出用户数据
</button>
</TableExporter>
</div>
);
};
优缺点分析
-
优点
:代码模块化,可复用性高;支持 .xlsx 格式(兼容性更好);支持JSON数据直接导出(无需依赖DOM);复杂表格(合并单元格、多工作表)处理更稳定。 -
缺点
:需引入外部依赖( xlsx 和 file-saver );打包体积略有增加(可通过Tree Shaking优化)。
番外:XLSX与SheetJS的关系
很多开发者会混淆 XLSX 与 SheetJS ,其实二者是"社区版"与"项目总称"的关系:
-
包含关系
:SheetJS是项目名称,包含社区版( xlsx 包)和专业版; xlsx 是SheetJS社区版在npm上的官方包名,开源免费。
-
功能差异
: xlsx 包支持基础的Excel读写、格式转换(如JSON/Table→Excel);SheetJS专业版额外提供模板编辑、图表生成等高级功能(需付费)。
-
使用统一
:日常开发中,通过 import XLSX from 'xlsx' 即可调用SheetJS社区版核心能力,无需额外配置。
方案选择建议
-
- 兼容性优先(如需支持IE):选择方案1(纯Blob+HTML拼接);
-
- 现代项目(React/Vue):选择方案2(XLSX库),代码更优雅、可复用性更高;
-
- 复杂表格(合并单元格、多工作表):必须选择方案2, xlsx 库对复杂格式的支持更稳定。