基于xlsx.js前端导出多sheet的Excel

1,976 阅读2分钟

提示: 该方法有性能问题,建议在导出数据小于500行的数据时候进行使用。数据量较多的情况下,依然推荐后端导出!

一. index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>excel导出</title>
  </head>
  <body>
    <button onclick="downLoad()">导出</button>
    <script src="./xlsx.core.min.js"></script>
    <script src="./02-多表导出.js"></script>
    <script src="./index02.js"></script>
  </body>
</html>

二、02-多表导出.js

;(function(window) {
  /**
   * 需要三个参数
   * @title: 文件名 字符串
   * @sheets: sheet名称 数组  ["瞬时流量(m³/h)", "液位(m)"]
   * @dataAll:相应数据    数组
   *
   * */

  // dataAll 的数据形式
  // [
  //   [['时间','m'],['2012','10'],['2012','10']], // sheet1
  //   [['时间','m'],['2012','10'],['2012','10']], // sheet2
  //   [['时间','m'],['2012','10'],['2012','10']], // ....
  // ]
  function exportExcel(title = 'demo', sheets = [], dataAll = []) {
    if (sheets.length === 0 || dataAll.length === 0) return
    //  数据处理
    // 第一步:数据格式处理
    let keyObj = {}
    let tmpObj = {}
    let tmpArr = []
    let SheetNames = []
    let Units = []
    // 第一次处理
    sheets.forEach(item => {
      let index = item.indexOf('(')
      let length = item.length
      if (index !== -1) {
        SheetNames.push(item.substr(0, index))
        Units.push(item.substring(index + 1, length - 1))
      } else {
        SheetNames.push(item)
        Units.push(item)
      }
    })
    //    添加 表头
    dataAll.forEach((item, index) => {
      item.unshift(['时间', Units[index]])
    })
    SheetNames.forEach((item, index) => {
      keyObj[index] = []
      tmpObj[index] = []
      dataAll[index].forEach((v, i) => {
        v.forEach((it, inx) => {
          let key = String.fromCharCode(65 + inx) + (i + 1)
          keyObj[index].push(key)
          tmpObj[index].push({
            position: key,
            v: it
          })
        })
      })
    })
    // 第二次处理
    for (let i in tmpObj) {
      tmpArr[i] = tmpObj[i].reduce(
        (prev, next) =>
          Object.assign({}, prev, {
            [next.position]: { v: next.v }
          }),
        {}
      )
    }
    // 第二步: 合成 Sheets
    let Sheets = {}
    SheetNames.forEach((item, index) => {
      let ref = keyObj[index][0] + ':' + keyObj[index][keyObj[index].length - 1]
      Sheets[item] = Object.assign({}, tmpArr[index], { '!ref': ref })
    })
    let wb = {
      SheetNames,
      Sheets
    }
    save(wb, `${title}${+new Date()}.xlsx`)
    // end
  }

  function save(wb, fileName) {
    let wopts = {
      bookType: 'xlsx',
      bookSST: false,
      type: 'binary'
    }
    let xw = XLSX.write(wb, wopts)
    let obj = new Blob([s2ab(xw)], {
      type: ''
    })
    let elem = document.createElement('a')
    elem.download = fileName || '下载'
    elem.href = URL.createObjectURL(obj)
    elem.click()
    setTimeout(function() {
      URL.revokeObjectURL(obj)
    }, 100)
  }
  function s2ab(s) {
    if (typeof ArrayBuffer !== 'undefined') {
      let buf = new ArrayBuffer(s.length)
      let view = new Uint8Array(buf)
      for (let i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff
      return buf
    } else {
      let buf = new Array(s.length)
      for (let i = 0; i != s.length; ++i) buf[i] = s.charCodeAt(i) & 0xff
      return buf
    }
  }
  window.exportExcel = exportExcel
})(window)

三、测试数据 index02.js

/**
 * 需要三个参数
 * @title: 文件名 字符串
 * @sheets: 指标名称 数组  ["瞬时流量(m³/h)", "液位(m)", "COD(mg/L)", "PH", "NH3-N(mg/L)"]
 * @dataAll:相应数据    数组
 *
 * */

// dataAll 的数据形式
// [
//   [['时间','m'],['2012','10'],['2012','10']], // sheet1
//   [['时间','m'],['2012','10'],['2012','10']], // sheet2
//   [['时间','m'],['2012','10'],['2012','10']], // ....
//
let sheets = ['aa', 'bb']
let dataAll = [
  [
    ['时间', '地址'],
    ['2011', 'a'],
    ['2012', 'b']
  ],
  [
    ['时间', '地址'],
    ['2011', 'c'],
    ['2012', 'd']
  ]
]
function downLoad() {
  exportExcel('多表导出', sheets, dataAll)
}