亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

JS前端導(dǎo)出Excel的方法詳解

 更新時(shí)間:2023年07月25日 08:26:47   作者:linwu  
最近寫(xiě)管理端的需求,發(fā)現(xiàn)有一個(gè)excel導(dǎo)出的需求,所以正好本文就來(lái)和大家分享一下導(dǎo)出excel文件的三種實(shí)現(xiàn)方式,感興趣的小伙伴可以了解一下

前言

最近寫(xiě)管理端的需求,發(fā)現(xiàn)有一個(gè)excel導(dǎo)出的需求,本來(lái)是后端同學(xué)負(fù)責(zé),但是因?yàn)樗麄兲α?,把這塊任務(wù)交給前端了,起初產(chǎn)品覺(jué)得前端實(shí)現(xiàn)不了,一聽(tīng)這話,這我哪里受得了,趕緊寫(xiě)了個(gè)demo給她看,前端是可以實(shí)現(xiàn)的。enen,產(chǎn)品看了直夸牛逼

接下來(lái),我來(lái)分享導(dǎo)出excel文件的三種實(shí)現(xiàn)方式

url下載

在這種方式中,我們的目標(biāo)是后端生成Excel文件并提供一個(gè)地址,前端通過(guò)訪問(wèn)這個(gè)地址來(lái)下載導(dǎo)出的Excel文件。

  • 后端根據(jù)前端的請(qǐng)求,生成需要導(dǎo)出的數(shù)據(jù),并將數(shù)據(jù)轉(zhuǎn)換為Excel格式的文件。
  • 后端將生成的Excel文件保存到服務(wù)器的某個(gè)臨時(shí)目錄,并為該文件生成一個(gè)臨時(shí)的訪問(wèn)地址。
  • 后端將生成的臨時(shí)地址返回給前端作為響應(yīng)。
  • 前端收到后端返回的地址后,可以通過(guò)創(chuàng)建一個(gè)隱藏的 <a> 標(biāo)簽,并設(shè)置其 href 屬性為后端返回的地址,然后觸發(fā)點(diǎn)擊該標(biāo)簽的操作,從而實(shí)現(xiàn)文件下載。
  • 前端完成下載后,可以根據(jù)需求決定是否刪除服務(wù)器上的臨時(shí)文件。
// 后端接口:/api/export/excel
// 請(qǐng)求方式:GET
// 假設(shè)后端接口返回導(dǎo)出地址的數(shù)據(jù)格式為 { url: "https://example.com/excel_exports/exported_file.xlsx" }
export const exportExcelViaURL = () => {
  // 發(fā)起后端接口請(qǐng)求獲取導(dǎo)出地址
  fetch('/api/export/excel')
    .then((response) => response.json())
    .then((data) => {
      const { url } = data;
      // 創(chuàng)建一個(gè)隱藏的<a>標(biāo)簽并設(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ā)點(diǎn)擊操作,開(kāi)始下載文件
      link.click();
    })
    .catch((error) => {
      console.error('導(dǎo)出Excel失敗:', error);
    });
};

Blob文件流

后端直接返回Blob文件流數(shù)據(jù),前端通過(guò)接收到的Blob數(shù)據(jù)進(jìn)行文件下載。

  • 后端根據(jù)前端的請(qǐng)求,生成需要導(dǎo)出的數(shù)據(jù),并將數(shù)據(jù)轉(zhuǎn)換為Excel格式的文件。
  • 后端將生成的Excel數(shù)據(jù)以Blob文件流的形式返回給前端,通常是通過(guò)設(shè)置響應(yīng)的Content-Type和Content-Disposition頭,使其以文件下載的方式呈現(xiàn)給用戶。
  • 前端通過(guò)接收到的Blob數(shù)據(jù),可以創(chuàng)建一個(gè)Blob URL,然后創(chuàng)建一個(gè)隱藏的 <a> 標(biāo)簽,并將其 href 屬性設(shè)置為Blob URL,再觸發(fā)點(diǎn)擊該標(biāo)簽的操作,從而實(shí)現(xiàn)文件下載。
// 后端接口:/api/export/excel/blob
// 請(qǐng)求方式:GET
export const exportExcelViaBlob = () => {
  // 發(fā)起后端接口請(qǐng)求獲取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)建一個(gè)隱藏的<a>標(biāo)簽并設(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ā)點(diǎn)擊操作,開(kāi)始下載文件
      link.click();
      // 釋放Blob URL
      URL.revokeObjectURL(blobUrl);
    })
    .catch((error) => {
      console.error('導(dǎo)出Excel失敗:', error);
    });
};

基于XLSX

XLSX是一款功能強(qiáng)大的JavaScript庫(kù),用于在瀏覽器和Node.js中讀取、解析、處理和寫(xiě)入Excel文件。

1. 安裝XLSX

首先,你需要在你的項(xiàng)目中安裝XLSX庫(kù)。你可以通過(guò)npm或yarn來(lái)安裝:

npm install xlsx

或者

yarn add xlsx

2. 引入XLSX

在你的代碼中,你需要引入XLSX庫(kù),以便使用其中的功能:

import * as XLSX from 'xlsx';

3. 讀取Excel文件

使用XLSX庫(kù),你可以讀取現(xiàn)有的Excel文件,提取其中的數(shù)據(jù)和元數(shù)據(jù)。例如,假設(shè)你有一個(gè)名為"data.xlsx"的Excel文件,你可以通過(guò)以下方式讀取它:

import * as XLSX from 'xlsx';
const file = 'data.xlsx'; // 文件路徑或URL
const workbook = XLSX.readFile(file);
const sheetName = workbook.SheetNames[0]; // 假設(shè)我們讀取第一個(gè)工作表
const worksheet = workbook.Sheets[sheetName];
const data = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
console.log(data);

4. 寫(xiě)入Excel文件

除了讀取現(xiàn)有的Excel文件,XLSX庫(kù)還允許你將數(shù)據(jù)寫(xiě)入到新的Excel文件中。例如,你可以將一個(gè)二維數(shù)組的數(shù)據(jù)寫(xiě)入到一個(gè)新的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);

項(xiàng)目實(shí)踐

下面代碼是我在項(xiàng)目中封裝好的代碼,有需要的同學(xué)直接copy使用就行

為了實(shí)現(xiàn)前述兩種方式的前端導(dǎo)出Excel功能,我們將使用XLSX庫(kù)來(lái)處理數(shù)據(jù)并導(dǎo)出Excel文件。

// 基于XLSX的前端導(dǎo)出Excel實(shí)現(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)建一個(gè)隱藏的<a>標(biāo)簽并設(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ā)點(diǎn)擊操作,開(kāi)始下載文件
  link.click();
  // 釋放Blob URL
  URL.revokeObjectURL(blobUrl);
};

下載全部

我們可能需要一鍵下載所有表格的數(shù)據(jù),這時(shí)候前端需要輪詢后端的接口,拿到所有的數(shù)據(jù),所以我們需要實(shí)現(xiàn)一個(gè)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)分頁(yè)請(qǐng)求,獲取全部數(shù)據(jù)
 * @param {Function} request 請(qǐng)求
 * @param {Number} size 頁(yè)大小
 * @param {Object} params 其余參數(shù)
 * @param {String} listLabel.pageLable 當(dāng)前頁(yè)字段名。默認(rèn)page
 * @param {String} listLabel.sizeLabel 頁(yè)大小字段名。默認(rèn)page_size
 * @param {String} listLabel.totalLabel 總條數(shù)字段名。默認(rèn)total
 * @param {String} listLabel.itemsLabel 數(shù)據(jù)列表字段名。默認(rèn)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的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于JS導(dǎo)出Excel的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JavaScript中的return布爾值的用法和原理解析

    JavaScript中的return布爾值的用法和原理解析

    這篇文章主要介紹了JavaScript中的return布爾值的用法和原理解析,需要的朋友可以參考下
    2017-08-08
  • javascript生成大小寫(xiě)字母

    javascript生成大小寫(xiě)字母

    本文給大家分享的是javascript生成大寫(xiě)小寫(xiě)字母的代碼,十分的簡(jiǎn)單實(shí)用,主要用到了str.charCodeAt()和 String.fromCharCode()方法,有需要的小伙伴可以參考下。
    2015-07-07
  • 用js實(shí)現(xiàn)CSS圓角生成更新

    用js實(shí)現(xiàn)CSS圓角生成更新

    用js實(shí)現(xiàn)CSS圓角生成更新...
    2007-05-05
  • 微信小程序?qū)崙?zhàn)篇之購(gòu)物車的實(shí)現(xiàn)代碼示例

    微信小程序?qū)崙?zhàn)篇之購(gòu)物車的實(shí)現(xiàn)代碼示例

    本篇文章主要介紹了微信小程序?qū)崙?zhàn)篇之購(gòu)物車的實(shí)現(xiàn)代碼示例,詳細(xì)的介紹了購(gòu)物車的功能實(shí)現(xiàn),具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-11-11
  • 從階乘函數(shù)對(duì)比Javascript和C#的異同

    從階乘函數(shù)對(duì)比Javascript和C#的異同

    今天學(xué)習(xí)Javascript函數(shù),發(fā)現(xiàn)這完全是一個(gè)神奇的東西。跟我們平常所見(jiàn)強(qiáng)類型語(yǔ)言中的函數(shù)有好多不同。下面我們就從C#和JavaScript的兩個(gè)計(jì)算階乘的函數(shù)中比較兩者的異同
    2012-05-05
  • 原生js開(kāi)發(fā)的日歷插件

    原生js開(kāi)發(fā)的日歷插件

    本文主要分享了原生js開(kāi)發(fā)的日歷插件的示例代碼。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-02-02
  • js 獲取元素的具體樣式信息getcss(實(shí)例講解)

    js 獲取元素的具體樣式信息getcss(實(shí)例講解)

    下面小編就為大家?guī)?lái)一篇js 獲取元素的具體樣式信息getcss(實(shí)例講解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-07-07
  • JavaScript實(shí)現(xiàn)簡(jiǎn)易計(jì)算器功能的兩種方法

    JavaScript實(shí)現(xiàn)簡(jiǎn)易計(jì)算器功能的兩種方法

    這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)簡(jiǎn)易計(jì)算器功能的兩種方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • 一文詳解JS私有屬性的6種實(shí)現(xiàn)方式

    一文詳解JS私有屬性的6種實(shí)現(xiàn)方式

    class是創(chuàng)建對(duì)象的模版,由一系列屬性和方法構(gòu)成,用于表示對(duì)同一概念的數(shù)據(jù)和操作。有的屬性和方法是對(duì)外的,但也有的是私有的。本文梳理了六種私有屬性的實(shí)現(xiàn)方式,需要的可以參考一下
    2022-03-03
  • JavaScript中的操作符==與===介紹

    JavaScript中的操作符==與===介紹

    這篇文章主要介紹了JavaScript中的操作符==與===介紹,本文講解了===操作符的判斷規(guī)則、==操作符的判斷規(guī)則,需要的朋友可以參考下
    2014-12-12

最新評(píng)論