2025年前端导出Excel实践:探索xlsl的实现方式

前端导出Excel实践:探索xlsl的实现方式点击在线阅读 体验更好 链接 现代 JavaScript 高级小册 链接 深入浅出 Dart 链接 现代 TypeScript 高级小册 链接 linwu 的算法笔记 链接 前言 最近写管理端的需求 发现有一个 excel 导出的需求 本来是后端同学负责 但是因为他们太忙了

大家好,我是讯享网,很高兴认识大家。
点击在线阅读,体验更好 链接
现代JavaScript高级小册 链接
深入浅出Dart 链接
现代TypeScript高级小册 链接
linwu的算法笔记📒 链接

前言

最近写管理端的需求,发现有一个excel导出的需求,本来是后端同学负责,但是因为他们太忙了,把这块任务交给前端了,起初产品觉得前端实现不了,一听这话,这我哪里受得了,赶紧写了个demo给她看,前端是可以实现的。enen,产品看了直夸牛逼

接下来,我来分享导出excel文件的三种实现方式

url下载

在这种方式中,我们的目标是后端生成Excel文件并提供一个地址,前端通过访问这个地址来下载导出的Excel文件。

  • 后端根据前端的请求,生成需要导出的数据,并将数据转换为Excel格式的文件。
  • 后端将生成的Excel文件保存到服务器的某个临时目录,并为该文件生成一个临时的访问地址。
  • 后端将生成的临时地址返回给前端作为响应。
  • 前端收到后端返回的地址后,可以通过创建一个隐藏的 <a> 标签,并设置其 href 属性为后端返回的地址,然后触发点击该标签的操作,从而实现文件下载。
  • 前端完成下载后,可以根据需求决定是否删除服务器上的临时文件。
// 后端接口:/api/export/excel // 请求方式:GET // 假设后端接口返回导出地址的数据格式为 { url: "https://example.com/excel_exports/exported_file.xlsx" } export const exportExcelViaURL = () => { 
    // 发起后端接口请求获取导出地址 fetch('/api/export/excel') .then((response) => response.json()) .then((data) => { 
    const { 
    url } = data; // 创建一个隐藏的<a>标签并设置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`; // 触发点击操作,开始下载文件 link.click(); }) .catch((error) => { 
    console.error('导出Excel失败:', error); }); }; 

讯享网

Blob文件流

后端直接返回Blob文件流数据,前端通过接收到的Blob数据进行文件下载。

  • 后端根据前端的请求,生成需要导出的数据,并将数据转换为Excel格式的文件。
  • 后端将生成的Excel数据以Blob文件流的形式返回给前端,通常是通过设置响应的Content-Type和Content-Disposition头,使其以文件下载的方式呈现给用户。


    讯享网

  • 前端通过接收到的Blob数据,可以创建一个Blob URL,然后创建一个隐藏的 <a> 标签,并将其 href 属性设置为Blob URL,再触发点击该标签的操作,从而实现文件下载。
讯享网// 后端接口:/api/export/excel/blob // 请求方式:GET export const exportExcelViaBlob = () => { 
    // 发起后端接口请求获取Blob文件流数据 fetch('/api/export/excel/blob') .then((response) => response.blob()) .then((blobData) => { 
    // 创建Blob URL const blobUrl = URL.createObjectURL(blobData); // 创建一个隐藏的<a>标签并设置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`; // 触发点击操作,开始下载文件 link.click(); // 释放Blob URL URL.revokeObjectURL(blobUrl); }) .catch((error) => { 
    console.error('导出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库,你可以读取现有的Excel文件,提取其中的数据和元数据。例如,假设你有一个名为"data.xlsx"的Excel文件,你可以通过以下方式读取它:

讯享网import * as XLSX from 'xlsx'; const file = 'data.xlsx'; // 文件路径或URL const workbook = XLSX.readFile(file); const sheetName = workbook.SheetNames[0]; // 假设我们读取第一个工作表 const worksheet = workbook.Sheets[sheetName]; const data = XLSX.utils.sheet_to_json(worksheet, { 
    header: 1 }); console.log(data); 

4. 写入Excel文件

除了读取现有的Excel文件,XLSX库还允许你将数据写入到新的Excel文件中。例如,你可以将一个二维数组的数据写入到一个新的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'; // 导出的文件名 XLSX.writeFile(workbook, fileName); 

项目实践

下面代码是我在项目中封装好的代码,有需要的同学直接copy使用就行

为了实现前述两种方式的前端导出Excel功能,我们将使用XLSX库来处理数据并导出Excel文件。

讯享网// 基于XLSX的前端导出Excel实现 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 定义列属性数组 * @param data 数据 * @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数据 const excelData = XLSX.write(workbook, { 
    type: 'array', bookType: 'xlsx' }); const blobData = new Blob([excelData], { 
    type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); // 创建Blob URL const blobUrl = URL.createObjectURL(blobData); // 创建一个隐藏的<a>标签并设置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`; // 触发点击操作,开始下载文件 link.click(); // 释放Blob URL URL.revokeObjectURL(blobUrl); }; 

下载全部

我们可能需要一键下载所有表格的数据,这时候前端需要轮询后端的接口,拿到所有的数据,所以我们需要实现一个loopReuqest函数

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; } / * 循环分页请求,获取全部数据 * @param {Function} request 请求 * @param {Number} size 页大小 * @param {Object} params 其余参数 * @param {String} listLabel.pageLable 当前页字段名。默认page * @param {String} listLabel.sizeLabel 页大小字段名。默认page_size * @param {String} listLabel.totalLabel 总条数字段名。默认total * @param {String} listLabel.itemsLabel 数据列表字段名。默认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 []; } 
小讯
上一篇 2025-02-10 23:54
下一篇 2025-03-19 21:41

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/22161.html