前端導出Excel在線指北

Hello, 各位勇敢的小夥伴, 你們好, 我是大家的嘴強王者小五, 身體健康, 腦子沒病.前端

本人有豐富的脫髮技巧, 能讓你一躍成爲資深大咖.git

一看就會一寫就廢是本人的主旨, 菜到摳腳是本人的特色, 卑微中透着一絲絲剛強, 傻人有傻福是對我最大的安慰.github

歡迎來到小五隨筆系列前端導出Excel在線指北.npm

寫在前面

雙手奉上代碼連接 傳送門 - ajun568後端

雙腳奉上最終效果圖數組

觀前提醒工具

👺 本文最終實現效果如上圖, 具體功能爲: 導出Excel + 多個Sheet + 可合併的多行表頭. 代碼部分採用 React+TS 做爲工具進行編寫.post

準備工做

👺 安裝 xlsx.js npm install xlsx搜索引擎

👺 寫入Excel文件: XLSX.write(workbook, writeOpts)編碼

workbook 👇

  • SheetNames @types string[]: 當前 Sheet 的名稱
  • Sheets: 當前sheet的對象, 格式以下
[SheetNames]: {
  "!refs": "A1:G7", // 表示從 第1行第A列 到 第7行第G列
  "!cols": [{wpx: 80} ... ], // 表示 列寬 80px
  "!rows": [{hpx: 20} ... ], // 表示 行高 20px
  "!merges": [{s: {r: 0, c: 2}, e: {r: 0, c: 3}} ... ], // 表示 將 第0行第2列 和 第0行第3列 進行合併 (s: start, e: end, c: column, r: row)
  "A1": {v: "姓名"}, // 表示第1行第A列 顯示數據爲 "姓名", 以此類推 ...
  ...
}

writeOpts 👇

{
  type, // 數據編碼, 本文采用 binary 二進制格式
  bookType, // 導出類型, 本文采用 xlsx 類型
  compression, // 是否使用 Gzip 壓縮
}

下載文件

想要下載文件, 我小A第一個表示不服, 申請出戰 <a 標籤的 download 屬性>

經過 URL.createObjectURL(Object) 來建立下載所需的 URL. 因爲每次調用都會產生新的 URL 對象, 故使用後記得釋放, 釋放方法 URL.revokeObjectURL(FileUrl)

經過模擬 click 事件觸發 a 標籤, 以實現下載

const saveAs = (obj: Blob, fileName?: string): void => {
  const temp = document.createElement('a')
  temp.download = fileName || 'download'
  temp.href = URL.createObjectURL(obj)
  temp.click()
  setTimeout(() =>  { URL.revokeObjectURL(temp.href) }, 100)
}

頭部處理

Mock數據: 詳細數據請跳轉 Github, 在 mock.ts 中查看

Header 部分數據格式

[
  ...
  {
    key: 'animal',
    value: '動物',
    child: [
      {
        key: 'dog',
        value: '狗',
        child: [
          {
            key: 'corgi',
            value: '柯基',
          },
          {
            key: 'husky',
            value: '哈士奇',
          },
        ],
      },
      {
        key: 'tiger',
        value: '老虎',
      },
    ],
  },
  ...
]

Data 部分數據格式

[
  {
    name: '黃刀小五',
    desc: '基於搜索引擎的複製粘貼攻城獅',
    watermelon: '喜歡',
    banana: '不喜歡',
    corgi: '喜歡',
    husky: '喜歡',
    tiger: '不喜歡',
  },
  ...
]

頭部數據處理

👺 分析

  • Header 數據爲樹形結構, 其深度爲頭部所佔行數
  • Header 數據要轉換成 Data 數據的格式, 並與 Data 數組合並, 共同處理成導出所需格式
  • 轉換對象的 key 應爲最小葉子結點的 key
  • 轉換對象的 value 應爲當前層級的 value ( 即導出後當前行所顯示的 value )
  • 既然是樹, 果斷遞歸, 準沒錯

🧟‍♂️ Code

excel2.png

🧟‍♂️ Image

Merged 數據

{
  s: { // start
    r: x, // row
    c: y, // column
  },
  e: { ... } // end
}

👺 分析

  • 將處理後的頭部數據當作一個矩陣
  • 行或列中, 相鄰元素若相同, 則進行合併

tips: 本文采用的是判斷相鄰 value 值是否相等進行合併, 如有需求, 建議改寫爲對象形式加以完善.

🧟‍♂️ Code

excel4.png

🧟‍♂️ Image

生成sheet數據

  • 利用Object.assign進行對象合併
  • 利用String.fromCharCode(65 + i)對列進行大寫字母的轉換

🧟‍♂️ Code

excel13.png

🧟‍♂️ Image

轉換字節流

利用 new ArrayBuffer(str) 建立一個緩衝區, 使用 new Uint8Array(buf) 引用

由於 unicode 編碼是 0~65535, 而 Uint8Array 範圍爲 0~255, 故須要按位與 0xFF, 以保持位數一致

const s2ab = (str: string): ArrayBuffer => {
  let buf = new ArrayBuffer(str.length)
  let view = new Uint8Array(buf)

  for (let i = 0; i !== str.length; ++i) {
    view[i] = str.charCodeAt(i) & 0xFF
  }

  return buf
}

導出文件

結合前文 準備工做 部分所講, 導出的代碼邏輯就出來了, 直接上代碼

excel14.png

結束語

開源版本不支持設置樣式, 如有需求, 可採用 付費版本 或使用 xlsx-style, 使用方法與本文一致. 你們可參照文檔自行添加樣式部分.

參考🔗連接

【Github】 SheetJS ~ js-xlsx

【mySoul】 優雅 | 先後端優雅的導入導出Excel

【Seefly】 前端使用xlsx.js導出有複雜表頭的excel

相關文章
相關標籤/搜索