前端無接口實(shí)現(xiàn)Table導(dǎo)出Excel的兩種方案
在日常開發(fā)中,表格數(shù)據(jù)導(dǎo)出Excel是高頻需求,多數(shù)場景下依賴后端接口返回二進(jìn)制文件實(shí)現(xiàn)下載。但當(dāng)無后端接口支持時(shí),前端也可通過純前端方案完成導(dǎo)出,以下是兩種實(shí)用方案的詳細(xì)實(shí)現(xiàn)與對比。
方案1:純前端Blob+HTML拼接方案(兼容所有瀏覽器)
該方案通過拼接HTML字符串模擬Excel結(jié)構(gòu),轉(zhuǎn)換為Blob對象后觸發(fā)下載,是早期無框架時(shí)代的經(jīng)典實(shí)現(xiàn)方式,兼容性覆蓋所有主流瀏覽器。
核心原理
1. 拼接包含Excel格式聲明的HTML字符串(引入微軟Office相關(guān)命名空間,確保Excel能正確解析); 2. 將HTML字符串轉(zhuǎn)為 Blob 對象,通過 URL.createObjectURL 生成臨時(shí)內(nèi)存地址; 3. 動態(tài)創(chuàng)建 a 標(biāo)簽指向該地址,觸發(fā)點(diǎn)擊事件完成下載,最后清理臨時(shí)資源避免內(nèi)存泄漏。
完整代碼
/**
* 純前端Blob方案導(dǎo)出Table為Excel
* @param {string} tableID - 頁面中表格的ID
* @param {string} filename - 導(dǎo)出文件的名稱(默認(rèn)export)
*/
function exportTableToExcel(tableID, filename = '') {
// 1. 獲取表格DOM元素,校驗(yàn)合法性
const table = document.getElementById(tableID);
if (!table) {
console.error('導(dǎo)出失?。何凑业絀D為「' + 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的兼容性配置:顯示網(wǎng)格線 -->
<!--[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. 創(chuàng)建Blob對象(指定Excel文件類型)
const blob = new Blob([html], { type: 'application/vnd.ms-excel' });
// 4. 動態(tài)創(chuàng)建下載鏈接并觸發(fā)下載
const link = document.createElement('a');
link.href = URL.createObjectURL(blob); // 生成Blob臨時(shí)URL
link.download = `${filename || 'export'}.xls`; // 定義下載文件名
document.body.appendChild(link); // 掛載到DOM(部分瀏覽器需顯式掛載才能觸發(fā)點(diǎn)擊)
link.click(); // 觸發(fā)下載
// 5. 清理臨時(shí)資源(避免內(nèi)存泄漏)
setTimeout(() => {
document.body.removeChild(link); // 移除臨時(shí)a標(biāo)簽
URL.revokeObjectURL(link.href); // 釋放Blob URL內(nèi)存
}, 100);
}
優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):無依賴,無需安裝任何包;兼容所有瀏覽器(包括IE)。缺點(diǎn):通過字符串拼接HTML,代碼冗余且易出錯;僅支持導(dǎo)出 .xls 格式(不支持 .xlsx );復(fù)雜表格(如合并單元格)可能解析異常。
方案2:基于XLSX庫的優(yōu)雅方案(推薦)
借助開源庫 xlsx (SheetJS社區(qū)版)處理表格數(shù)據(jù)與Excel格式轉(zhuǎn)換,搭配 file-saver 優(yōu)化下載邏輯,代碼可復(fù)用性高,支持復(fù)雜表格與 .xlsx 格式。
前置準(zhǔn)備:安裝依賴
npm install xlsx file-saver --save
xlsx:SheetJS社區(qū)版核心庫,負(fù)責(zé)表格數(shù)據(jù)與Excel格式的轉(zhuǎn)換;file-saver:簡化Blob對象下載邏輯,解決跨瀏覽器兼容性問題。
1. 基礎(chǔ)版:直接導(dǎo)出頁面Table
適用于需導(dǎo)出頁面已渲染好的Table場景,直接從DOM解析表格數(shù)據(jù)。
import * as XLSX from 'xlsx';
import { saveAs } from 'file-saver';
/**
* 基于XLSX導(dǎo)出頁面Table為Excel
* @param {string} tableId - 頁面表格ID
* @param {string} fileName - 導(dǎo)出文件名稱(默認(rèn)export)
* @param {string} sheetName - Excel工作表名稱(默認(rèn)Sheet1)
*/
const exportExcelFromTable = (tableId, fileName = 'export', sheetName = 'Sheet1') => {
try {
// 1. 獲取表格DOM并轉(zhuǎn)為Excel工作表(worksheet)
const table = document.getElementById(tableId);
if (!table) {
console.error('導(dǎo)出失敗:未找到指定Table元素');
return;
}
const worksheet = XLSX.utils.table_to_sheet(table); // DOM → 工作表
// 2. 創(chuàng)建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', // 導(dǎo)出格式(xlsx/xls/csv等)
type: 'array' // 輸出類型為ArrayBuffer
});
const blob = new Blob([excelBuffer], { type: 'application/octet-stream' });
saveAs(blob, `${fileName}.xlsx`); // 觸發(fā)下載
} catch (error) {
console.error('Excel導(dǎo)出失?。?, error);
}
};
2. 進(jìn)階版:React導(dǎo)出組件(可復(fù)用)
適用于React項(xiàng)目,支持通過 data 和 columns 配置導(dǎo)出(無需依賴頁面DOM),可直接集成到業(yè)務(wù)組件中。
import React from 'react';
import * as XLSX from 'xlsx';
import { saveAs } from 'file-saver';
/**
* React Table導(dǎo)出Excel組件
* @param {Array} data - 表格數(shù)據(jù)源(數(shù)組對象,如[{id:1, name:'xxx'}, ...])
* @param {Array} columns - 表格列配置(如[{title:'ID', dataIndex:'id'}, ...])
* @param {string} fileName - 導(dǎo)出文件名(默認(rèn)export)
* @param {string} sheetName - 工作表名稱(默認(rèn)Sheet1)
* @param {string} buttonLabel - 導(dǎo)出按鈕文本(默認(rèn)"導(dǎo)出Excel")
* @param {Object} buttonStyle - 按鈕自定義樣式
* @param {ReactNode} children - 自定義觸發(fā)元素(如按鈕、圖標(biāo))
*/
const TableExporter = ({
data = [],
columns = [],
fileName = 'export',
sheetName = 'Sheet1',
buttonLabel = '導(dǎo)出Excel',
buttonStyle = {},
children
}) => {
const exportToExcel = () => {
try {
// 1. 處理數(shù)據(jù):根據(jù)columns匹配表頭與數(shù)據(jù)
const formattedData = data.map(row => {
const rowData = {};
columns.forEach(col => {
rowData[col.title] = row[col.dataIndex]; // 表頭→數(shù)據(jù)映射
});
return rowData;
});
// 2. 創(chuàng)建工作表與工作簿
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導(dǎo)出失?。?, error);
}
};
// 支持自定義觸發(fā)元素(如傳入按鈕、圖標(biāo)),無children則使用默認(rèn)按鈕
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;
組件使用示例
// 在業(yè)務(wù)組件中使用
import TableExporter from './TableExporter';
const BusinessComponent = () => {
// 表格數(shù)據(jù)源
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>
{/* 使用默認(rèn)按鈕 */}
<TableExporter
data={tableData}
columns={tableColumns}
fileName="用戶列表"
/>
{/* 自定義觸發(fā)元素(如Icon按鈕) */}
<TableExporter
data={tableData}
columns={tableColumns}
fileName="用戶列表"
>
<button style={{ marginLeft: '10px' }}>
<<i className="icon-export"></</i> 導(dǎo)出用戶數(shù)據(jù)
</button>
</TableExporter>
</div>
);
};
優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):代碼模塊化,可復(fù)用性高;支持 .xlsx 格式(兼容性更好);支持JSON數(shù)據(jù)直接導(dǎo)出(無需依賴DOM);復(fù)雜表格(合并單元格、多工作表)處理更穩(wěn)定。缺點(diǎn):需引入外部依賴( xlsx 和 file-saver );打包體積略有增加(可通過Tree Shaking優(yōu)化)。
番外:XLSX與SheetJS的關(guān)系
很多開發(fā)者會混淆 XLSX 與 SheetJS ,其實(shí)二者是“社區(qū)版”與“項(xiàng)目總稱”的關(guān)系:
- 1.
包含關(guān)系:SheetJS是項(xiàng)目名稱,包含社區(qū)版( xlsx 包)和專業(yè)版; xlsx 是SheetJS社區(qū)版在npm上的官方包名,開源免費(fèi)。 - 2.
功能差異: xlsx 包支持基礎(chǔ)的Excel讀寫、格式轉(zhuǎn)換(如JSON/Table→Excel);SheetJS專業(yè)版額外提供模板編輯、圖表生成等高級功能(需付費(fèi))。 - 3.
使用統(tǒng)一:日常開發(fā)中,通過 import XLSX from 'xlsx' 即可調(diào)用SheetJS社區(qū)版核心能力,無需額外配置。
方案選擇建議
- 1. 兼容性優(yōu)先(如需支持IE):選擇方案1(純Blob+HTML拼接);
- 2. 現(xiàn)代項(xiàng)目(React/Vue):選擇方案2(XLSX庫),代碼更優(yōu)雅、可復(fù)用性更高;
- 3. 復(fù)雜表格(合并單元格、多工作表):必須選擇方案2, xlsx 庫對復(fù)雜格式的支持更穩(wěn)定。
以上就是前端無接口實(shí)現(xiàn)Table導(dǎo)出Excel的兩種方案的詳細(xì)內(nèi)容,更多關(guān)于前端Table導(dǎo)出Excel的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
ES6基礎(chǔ)之?dāng)?shù)組和對象的拓展實(shí)例詳解
這篇文章主要介紹了ES6基礎(chǔ)之?dāng)?shù)組和對象的拓展,結(jié)合實(shí)例形式詳細(xì)分析了ES6數(shù)組和對象拓展運(yùn)算符、拓展方法的使用及相關(guān)操作技巧,需要的朋友可以參考下2019-08-08
JavaScript實(shí)現(xiàn)強(qiáng)制重定向至HTTPS頁面
這篇文章主要介紹了JavaScript實(shí)現(xiàn)強(qiáng)制重定向至HTTPS頁面,本文講解如何用JS實(shí)現(xiàn)HTTP重定向HTTPS或者HTTPS跳轉(zhuǎn)到HTTP,需要的朋友可以參考下2015-06-06
JavaScript常見事件處理程序?qū)嵗偨Y(jié)
這篇文章主要介紹了JavaScript常見事件處理程序,結(jié)合實(shí)例形式總結(jié)分析了javascript HTML事件、DOM事件、IE事件等相關(guān)處理程序與操作技巧,需要的朋友可以參考下2019-01-01
Bootstrap學(xué)習(xí)筆記之css組件(3)
這篇文章主要為大家詳細(xì)介紹了bootstrap學(xué)習(xí)筆記中的css組件,感興趣的小伙伴們可以參考一下2016-06-06
基于JS實(shí)現(xiàn)bookstore靜態(tài)頁面的實(shí)例代碼
本文給大家分享一段核心代碼基于js實(shí)現(xiàn)的bookstore靜態(tài)頁面,代碼簡單易懂,非常不錯,具有參考借鑒價(jià)值,需要的朋友參考下2017-02-02

