JS前端導(dǎo)出Excel的方法詳解
前言
最近寫管理端的需求,發(fā)現(xiàn)有一個excel導(dǎo)出的需求,本來是后端同學(xué)負責(zé),但是因為他們太忙了,把這塊任務(wù)交給前端了,起初產(chǎn)品覺得前端實現(xiàn)不了,一聽這話,這我哪里受得了,趕緊寫了個demo給她看,前端是可以實現(xiàn)的。enen,產(chǎn)品看了直夸牛逼
接下來,我來分享導(dǎo)出excel文件的三種實現(xiàn)方式
url下載
在這種方式中,我們的目標是后端生成Excel文件并提供一個地址,前端通過訪問這個地址來下載導(dǎo)出的Excel文件。
- 后端根據(jù)前端的請求,生成需要導(dǎo)出的數(shù)據(jù),并將數(shù)據(jù)轉(zhuǎn)換為Excel格式的文件。
- 后端將生成的Excel文件保存到服務(wù)器的某個臨時目錄,并為該文件生成一個臨時的訪問地址。
- 后端將生成的臨時地址返回給前端作為響應(yīng)。
- 前端收到后端返回的地址后,可以通過創(chuàng)建一個隱藏的
<a>
標簽,并設(shè)置其href
屬性為后端返回的地址,然后觸發(fā)點擊該標簽的操作,從而實現(xiàn)文件下載。 - 前端完成下載后,可以根據(jù)需求決定是否刪除服務(wù)器上的臨時文件。
// 后端接口:/api/export/excel // 請求方式:GET // 假設(shè)后端接口返回導(dǎo)出地址的數(shù)據(jù)格式為 { url: "https://example.com/excel_exports/exported_file.xlsx" } export const exportExcelViaURL = () => { // 發(fā)起后端接口請求獲取導(dǎo)出地址 fetch('/api/export/excel') .then((response) => response.json()) .then((data) => { const { url } = data; // 創(chuàng)建一個隱藏的<a>標簽并設(shè)置href屬性為后端返回的地址 const link = document.createElement('a'); link.href = url; link.target = '_blank'; link.download = `exported_data_${dayjs().format('YYYY-MM-DD_hh.mm.ss_a')}.xlsx`; // 觸發(fā)點擊操作,開始下載文件 link.click(); }) .catch((error) => { console.error('導(dǎo)出Excel失敗:', error); }); };
Blob文件流
后端直接返回Blob文件流數(shù)據(jù),前端通過接收到的Blob數(shù)據(jù)進行文件下載。
- 后端根據(jù)前端的請求,生成需要導(dǎo)出的數(shù)據(jù),并將數(shù)據(jù)轉(zhuǎn)換為Excel格式的文件。
- 后端將生成的Excel數(shù)據(jù)以Blob文件流的形式返回給前端,通常是通過設(shè)置響應(yīng)的Content-Type和Content-Disposition頭,使其以文件下載的方式呈現(xiàn)給用戶。
- 前端通過接收到的Blob數(shù)據(jù),可以創(chuàng)建一個Blob URL,然后創(chuàng)建一個隱藏的
<a>
標簽,并將其href
屬性設(shè)置為Blob URL,再觸發(fā)點擊該標簽的操作,從而實現(xiàn)文件下載。
// 后端接口:/api/export/excel/blob // 請求方式:GET export const exportExcelViaBlob = () => { // 發(fā)起后端接口請求獲取Blob文件流數(shù)據(jù) fetch('/api/export/excel/blob') .then((response) => response.blob()) .then((blobData) => { // 創(chuàng)建Blob URL const blobUrl = URL.createObjectURL(blobData); // 創(chuàng)建一個隱藏的<a>標簽并設(shè)置href屬性為Blob URL const link = document.createElement('a'); link.href = blobUrl; link.target = '_blank'; link.download = `exported_data_${dayjs().format('YYYY-MM-DD_hh.mm.ss_a')}.xlsx`; // 觸發(fā)點擊操作,開始下載文件 link.click(); // 釋放Blob URL URL.revokeObjectURL(blobUrl); }) .catch((error) => { console.error('導(dǎo)出Excel失敗:', error); }); };
基于XLSX
XLSX是一款功能強大的JavaScript庫,用于在瀏覽器和Node.js中讀取、解析、處理和寫入Excel文件。
1. 安裝XLSX
首先,你需要在你的項目中安裝XLSX庫。你可以通過npm或yarn來安裝:
npm install xlsx
或者
yarn add xlsx
2. 引入XLSX
在你的代碼中,你需要引入XLSX庫,以便使用其中的功能:
import * as XLSX from 'xlsx';
3. 讀取Excel文件
使用XLSX庫,你可以讀取現(xiàn)有的Excel文件,提取其中的數(shù)據(jù)和元數(shù)據(jù)。例如,假設(shè)你有一個名為"data.xlsx"的Excel文件,你可以通過以下方式讀取它:
import * as XLSX from 'xlsx'; const file = 'data.xlsx'; // 文件路徑或URL const workbook = XLSX.readFile(file); const sheetName = workbook.SheetNames[0]; // 假設(shè)我們讀取第一個工作表 const worksheet = workbook.Sheets[sheetName]; const data = XLSX.utils.sheet_to_json(worksheet, { header: 1 }); console.log(data);
4. 寫入Excel文件
除了讀取現(xiàn)有的Excel文件,XLSX庫還允許你將數(shù)據(jù)寫入到新的Excel文件中。例如,你可以將一個二維數(shù)組的數(shù)據(jù)寫入到一個新的Excel文件:
import * as XLSX from 'xlsx'; const data = [ ['Name', 'Age', 'City'], ['John Doe', 30, 'New York'], ['Jane Smith', 25, 'San Francisco'], ]; const worksheet = XLSX.utils.aoa_to_sheet(data); const workbook = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1'); const fileName = 'output.xlsx'; // 導(dǎo)出的文件名 XLSX.writeFile(workbook, fileName);
項目實踐
下面代碼是我在項目中封裝好的代碼,有需要的同學(xué)直接copy使用就行
為了實現(xiàn)前述兩種方式的前端導(dǎo)出Excel功能,我們將使用XLSX庫來處理數(shù)據(jù)并導(dǎo)出Excel文件。
// 基于XLSX的前端導(dǎo)出Excel實現(xiàn) import dayjs from 'dayjs'; import * as XLSX from 'xlsx'; /** * eg: .columns = [ * { header: 'Id', key: 'id', wpx: 10 }, * { header: 'Name', key: 'name', wch: 32 }, * { header: 'D.O.B.', key: 'dob', width: 10, hidden: true } * ] * data: [{id: 1, name: 'John Doe', dob: new Date(1970,1,1)}] * @param columns 定義列屬性數(shù)組 * @param data 數(shù)據(jù) * @param name 文件名 */ export const generateExcel = (columns = [], data = [], name = '') => { const headers = columns.map((item) => item.header); // https://docs.sheetjs.com/docs/csf/features/#row-and-column-properties const otherConfigs = columns.map(({ key, header, ...item }) => item); const dataList = data.map((item) => { let obj = {}; columns.forEach((col) => { obj[col.header] = item[col.key]; }); return obj; }); const workbook = XLSX.utils.book_new(); workbook.SheetNames.push(name); const worksheet = XLSX.utils.json_to_sheet(dataList, { header: headers, }); worksheet['!cols'] = otherConfigs; workbook.Sheets[name] = worksheet; // 生成Blob數(shù)據(jù) const excelData = XLSX.write(workbook, { type: 'array', bookType: 'xlsx' }); const blobData = new Blob([excelData], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); // 創(chuàng)建Blob URL const blobUrl = URL.createObjectURL(blobData); // 創(chuàng)建一個隱藏的<a>標簽并設(shè)置href屬性為Blob URL const link = document.createElement('a'); link.href = blobUrl; link.target = '_blank'; link.download = `${name}-${dayjs().format('YYYY-MM-DD_hh.mm.ss_a')}.xlsx`; // 觸發(fā)點擊操作,開始下載文件 link.click(); // 釋放Blob URL URL.revokeObjectURL(blobUrl); };
下載全部
我們可能需要一鍵下載所有表格的數(shù)據(jù),這時候前端需要輪詢后端的接口,拿到所有的數(shù)據(jù),所以我們需要實現(xiàn)一個loopReuqest函數(shù)
export default function awaitRequest(limit = 5) { let awaitTask = []; let currentTaskNum = 0; function run(event, ...args) { return new Promise((resolve, reject) => { function callbackEvent() { currentTaskNum++; event(...args) .then((res) => { if (awaitTask.length) { const nextTask = awaitTask.shift(); nextTask(); } resolve(res); }) .catch((e) => { console.error(e); reject(e); }) .finally(() => { currentTaskNum--; }); } if (currentTaskNum >= limit) { awaitTask.push(callbackEvent); } else { callbackEvent(); } }); } Object.defineProperties(run, { clear: { value: () => { awaitTask = []; }, }, }); return run; } /** * 循環(huán)分頁請求,獲取全部數(shù)據(jù) * @param {Function} request 請求 * @param {Number} size 頁大小 * @param {Object} params 其余參數(shù) * @param {String} listLabel.pageLable 當(dāng)前頁字段名。默認page * @param {String} listLabel.sizeLabel 頁大小字段名。默認page_size * @param {String} listLabel.totalLabel 總條數(shù)字段名。默認total * @param {String} listLabel.itemsLabel 數(shù)據(jù)列表字段名。默認list * @returns */ export async function loopRequest( request, size, params, listLabel = { totalLabel: 'total', pageLable: 'page', sizeLabel: 'page_size', itemsLabel: 'list', }, ) { const { totalLabel = 'total', pageLable = 'page', sizeLabel = 'page_size', itemsLabel = 'list' } = listLabel; try { const firstRes = await request({ ...params, [sizeLabel]: size, [pageLable]: 1, }); let list = firstRes.data[itemsLabel] || []; const total = firstRes.data[totalLabel]; if (total > size) { const limit = awaitRequest(); const restRequest = Array.from({ length: Math.floor(total / size), }).map((_, index) => limit(() => request({ ...params, [sizeLabel]: size, [pageLable]: index + 2, }), ), ); const resetRes = await Promise.all(restRequest); resetRes.forEach((res) => { if (res.code === 0 && res.data[itemsLabel]) { list.push(...res.data[itemsLabel]); } }); } return list; } catch (e) { console.error(e); } return []; }
以上就是JS前端導(dǎo)出Excel的方法詳解的詳細內(nèi)容,更多關(guān)于JS導(dǎo)出Excel的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
微信小程序?qū)崙?zhàn)篇之購物車的實現(xiàn)代碼示例
本篇文章主要介紹了微信小程序?qū)崙?zhàn)篇之購物車的實現(xiàn)代碼示例,詳細的介紹了購物車的功能實現(xiàn),具有一定的參考價值,有興趣的可以了解一下2017-11-11JavaScript實現(xiàn)簡易計算器功能的兩種方法
這篇文章主要為大家詳細介紹了JavaScript實現(xiàn)簡易計算器功能的兩種方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-07-07