vue.js中export2excel.js的使用,导出复杂表头excel文件

593 阅读1分钟

1、在utils目录引入export2excel.js

import { saveAs } from 'file-saver'
import XLSX from 'xlsx'

function generateArray(table) {
  var out = []
  var rows = table.querySelectorAll('tr')
  var ranges = []
  for (var R = 0; R < rows.length; ++R) {
    var outRow = []
    var row = rows[R]
    var columns = row.querySelectorAll('td')
    for (var C = 0; C < columns.length; ++C) {
      var cell = columns[C]
      var colspan = cell.getAttribute('colspan')
      var rowspan = cell.getAttribute('rowspan')
      var cellValue = cell.innerText
      if (cellValue !== '' && cellValue == +cellValue) cellValue = +cellValue

      // Skip ranges
      ranges.forEach(function(range) {
        if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) {
          for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null)
        }
      })

      // Handle Row Span
      if (rowspan || colspan) {
        rowspan = rowspan || 1
        colspan = colspan || 1
        ranges.push({
          s: {
            r: R,
            c: outRow.length
          },
          e: {
            r: R + rowspan - 1,
            c: outRow.length + colspan - 1
          }
        })
      }

      // Handle Value
      outRow.push(cellValue !== '' ? cellValue : null)

      // Handle Colspan
      if (colspan) { for (var k = 0; k < colspan - 1; ++k) outRow.push(null) }
    }
    out.push(outRow)
  }
  return [out, ranges]
}

function datenum(v, date1904) {
  if (date1904) v += 1462
  var epoch = Date.parse(v)
  return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000)
}

function sheet_from_array_of_arrays(data, opts) {
  var ws = {}
  var range = {
    s: {
      c: 10000000,
      r: 10000000
    },
    e: {
      c: 0,
      r: 0
    }
  }
  for (var R = 0; R != data.length; ++R) {
    for (var C = 0; C != data[R].length; ++C) {
      if (range.s.r > R) range.s.r = R
      if (range.s.c > C) range.s.c = C
      if (range.e.r < R) range.e.r = R
      if (range.e.c < C) range.e.c = C
      var cell = {
        v: data[R][C]
      }
      if (cell.v == null) continue

      var cell_ref = XLSX.utils.encode_cell({
        c: C,
        r: R
      })

      if (typeof cell.v === 'number') cell.t = 'n'
      else if (typeof cell.v === 'boolean') cell.t = 'b'
      else if (cell.v instanceof Date) {
        cell.t = 'n'
        cell.z = XLSX.SSF._table[14]
        cell.v = datenum(cell.v)
      } else cell.t = 's'

      ws[cell_ref] = cell
    }
  }
  if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range)
  return ws
}

function Workbook() {
  if (!(this instanceof Workbook)) return new Workbook()
  this.SheetNames = []
  this.Sheets = {}
}

function s2ab(s) {
  var buf = new ArrayBuffer(s.length)
  var view = new Uint8Array(buf)
  for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF
  return buf
}

export function export_table_to_excel(id) {
  var theTable = document.getElementById(id)
  var oo = generateArray(theTable)
  var ranges = oo[1]

  /* original data */
  var data = oo[0]
  var ws_name = 'SheetJS'

  var wb = new Workbook(),
    ws = sheet_from_array_of_arrays(data)

  /* add ranges to worksheet */
  // ws['!cols'] = ['apple', 'banan'];
  ws['!merges'] = ranges

  /* add worksheet to workbook */
  wb.SheetNames.push(ws_name)
  wb.Sheets[ws_name] = ws

  var wbout = XLSX.write(wb, {
    bookType: 'xlsx',
    bookSST: false,
    type: 'binary'
  })

  saveAs(new Blob([s2ab(wbout)], {
    type: 'application/octet-stream'
  }), 'test.xlsx')
}

export function export_json_to_excel({
  multiHeader = [],
  header,
  data,
  filename,
  merges = [],
  autoWidth = true,
  bookType = 'xlsx'
} = {}) {
  /* original data */
  filename = filename || 'excel-list'
  data = [...data]
  data.unshift(header)

  for (let i = multiHeader.length - 1; i > -1; i--) {
    data.unshift(multiHeader[i])
  }

  var ws_name = 'SheetJS'
  var wb = new Workbook(),
    ws = sheet_from_array_of_arrays(data)

  if (merges.length > 0) {
    if (!ws['!merges']) ws['!merges'] = []
    merges.forEach(item => {
      ws['!merges'].push(XLSX.utils.decode_range(item))
    })
  }

  if (autoWidth) {
    /* 设置worksheet每列的最大宽度*/
    const colWidth = data.map(row => row.map(val => {
      /* 先判断是否为null/undefined*/
      if (val == null) {
        return {
          'wch': 10
        }
      }
      /* 再判断是否为中文*/
      else if (val.toString().charCodeAt(0) > 255) {
        return {
          'wch': val.toString().length * 2
        }
      } else {
        return {
          'wch': val.toString().length * 1.5
        }
      }
    }))
    /* 以第一行为初始值*/
    const result = colWidth[0]
    for (let i = 1; i < colWidth.length; i++) {
      for (let j = 0; j < colWidth[i].length; j++) {
        if (result[j]['wch'] < colWidth[i][j]['wch']) {
          result[j]['wch'] = colWidth[i][j]['wch']
        }
      }
    }
    ws['!cols'] = result
  }

  /* add worksheet to workbook */
  wb.SheetNames.push(ws_name)
  wb.Sheets[ws_name] = ws
  var dataInfo = wb.Sheets[wb.SheetNames[0]]
  // 设置单元格框线
  const borderAll = {
    top: {
      style: 'thin'
    },
    bottom: {
      style: 'thin'
    },
    left: {
      style: 'thin'
    },
    right: {
      style: 'thin'
    }
  }
  // 给所有单元格加上边框,内容居中,字体,字号,标题表头特殊格式部分后面替换
  for (var i in dataInfo) {
    if (i == '!ref' || i == '!merges' || i == '!cols' || i == '!rows') { } else {
      dataInfo[i + ''].s = {
        border: borderAll,
        alignment: {
          horizontal: 'center',
          vertical: 'center'
        },
        font: {
          name: '微软雅黑',
          sz: 13
        }
      }
    }
  }

  var wbout = XLSX.write(wb, {
    bookType: bookType,
    bookSST: false,
    type: 'binary'
  })
  saveAs(new Blob([s2ab(wbout)], {
    type: 'application/octet-stream'
  }), `${filename}.${bookType}`)
}

2、在导出功能文件中引入export2excel.js中的导出方法

import { export_json_to_excel } from '@/utils/export2excel'

3、构建导出数据,执行导出

exportFile() {
    //multiHeader 复杂表头结构
    const multiHeader = [
    [
      '地区',
      '家畜', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
      '家禽', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
      '蜂',
      '实验性动物(只)',
      '特种畜禽', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
      '野生动物', '', '', '',
      '犬',
      '猫',
      '出具检疫证明',
      '合计'
    ],
    [
      '',
      '猪(头)', '', '', '', '',
      '牛(头)', '', '', '', '',
      '羊(头)', '', '', '', '', '',
      '其他家畜(头)',
      '鸡(只)', '', '', '', '', '',
      '鸭(只)', '', '', '', '', '',
      '鹅(只)', '', '', '', '', '',
      '鸽(只)',
      '鹌鹑(只)',
      '其他家禽(只)',
      '蜜蜂(只)',
      '',
      '水貂(非食用)(只)', '貂(非食用)(只)', '羊驼(只)', '火鸡(只)', '珍珠鸡(只)', '雏鸡(只)', '鹧鸪(只)', '番鸭(只)', '绿头鸭(只)', '鸵鸟(只)', '鸸鹋(只)', '银狐(非食用)(只)', '北极狐(非食用)(只)', '鹿', '', '', '小计', // 特殊畜禽
      '野生哺乳类动物(只)', '野生禽鸟类动物(只)', '其他野生动物(只)', '小计',
      '', // 犬
      '', // 猫
      '', // 出具检疫证明
      '' // 合计
    ]
    ]
    // header 最有一层表头
    const header = [
    '', // 地区
    '仔猪', '商品猪', '种猪', '其他猪', '小计',
    '肉牛', '奶牛', '种公牛', '其他牛', '小计',
    '绵羊', '山羊', '奶山羊', '种羊', '其他羊', '小计',
    '',
    '肉鸡', '蛋鸡', '雏鸡', '种鸡', '其他鸡', '小计',
    '肉鸭', '蛋鸭', '雏鸭', '种鸭', '其他鸭', '小计',
    '肉鹅', '蛋鹅', '雏鹅', '种鹅', '其他鹅', '小计',
    '',
    '',
    '',
    '',
    '', // 实验性动物
    '', '', '', '', '', '', '', '', '', '', '', '', '', '梅花鹿(只)', '马鹿(只)', '驯鹿(只)', '', // 特殊畜禽
    '', '', '', '', // 野生动物
    '', // 犬
    '', // 猫
    '', // 出具检疫证明
    '' // 合计
    ]

    // merges excel 单元格合并列的计算
    const merges = [
    'A1:A3', // 地区
    'B1:R1', 'B2:F2', 'G2:K2', 'L2:Q2', 'R2:R3', // 家畜
    'S1:AM1', 'S2:X2', 'Y2:AD2', 'AE2:AJ2', 'AK2:AK3', 'AL2:AL3', 'AM1:AM1', 'AM2:AM3', // 家禽
    'AN1:AN1', 'AN2:AN3', // 蜂
    'AO1:AO3', // 实验性动物
    'AP1:BF1', 'AP2:AP3', 'AQ2:AQ3', 'AR2:AR3', 'AS2:AS3', 'AT2:AT3', 'AU2:AU3', 'AV2:AV3', 'AW2:AW3', 'AX2:AX3', 'AY2:AY3', 'AZ2:AZ3', 'BA2:BA3', 'BB2:BB3', 'BC2:BE2', 'BF2:BF3', // 特殊畜禽
    'BG1:BJ1', 'BG2:BG3', 'BH2:BH3', 'BI2:BI3', 'BJ2:BJ3', // 野生动物
    'BK1:BK3', 'BL1:BL3', 'BM1:BM3', 'BN1:BN3'
    ]

    const filterVal = [
    'AREANAME', // 地区
    'ZAIZ', 'SHANGPZ', 'ZHONGZ', 'QITZ', 'pigTotal', // 猪
    'ROUN', 'NAIN', 'ZHONGGN', 'QITN', 'cowTotal', // 牛
    'MIANY', 'SHANY', 'NAISY', 'ZHONGYANG', 'QITYANG', 'sheepTotal', // 羊
    'QITJC', // 其他家畜
    'ROUJ', 'DANJ', 'CHUJ', 'ZHONGJ', 'QITJ', 'chickenTotal', // 鸡
    'ROUY', 'DANY', 'CHUY', 'ZHONGYA', 'QITYA', 'duckTotal', // 鸭
    'ROUE', 'DANE', 'CHUE', 'ZHONGE', 'QITE', 'gooseTotal', // 鹅
    'GE', // 鸽
    'ANC', // 鹌鹑
    'QITJQ', // 其他家禽
    'MIF', // 蜜蜂
    'QITSYDW', // 实验性动物
    'SHUID', // 水貂(非食用)
    'HE', // 貉(非食用)
    'YANGT', // 羊驼
    'HUOJ', // 火鸡
    'ZHENGZJ', // 珍珠鸡
    'ZHIJ', // 雉鸡
    'ZHEG', // 鹧鸪
    'FANY', // 番鸭
    'LVTY', // 绿头鸭
    'TUON', // 鸵鸟
    'ERM', // 鸸鹋
    'YINH', // 银狐(非食用)
    'BEIJH', // 北极狐(非食用)
    'MEIHL', // 梅花鹿
    'MAL', // 马鹿
    'XUNL', // 驯鹿
    'specialAnimalTotal', // 特殊畜禽小计
    'YESPRLDW', // 野生哺乳类动物
    'YESQLLDW', // 野生禽鸟类动物
    'QITYSDW', // 其他野生动物
    'wildAnimalTotal', // 野生动物小计
    'MAO', // 猫
    'QUAN', // 犬
    'NUMTOTAL', // 出具检疫证明
    'allTotal' // 合计
    ]
    const data = this.formatJson(res.data, filterVal)
    export_json_to_excel({
    multiHeader,
    header,
    data,
    filename: 'excel导出表格', // excel文件名
    merges
    })
},
// 导出数据构建
formatJson(data, filterVal) {
  return data.map(v => filterVal.map(j => {
    return v[j]
  }))
},

导出结果 1642121830(1).jpg 不喜勿喷,个人笔记而已