博客 / 詳情

返回

vue導出excel表格並設置表格樣式(vxe-table)

1.安裝

npm install xlsx --save
npm install xlsx-style --save
(安裝xlsx-style後會報錯,解決方案:https://blog.csdn.net/HDdgut/article/details/115356719)

2.導出並加表格樣式流程

創建excel文件
創建一個sheet
將sheet放進excel裏

將已有列表數據整理成想要的格式(如:標題 表頭 數據行)
將該數據轉成sheet格式(aoa_to_sheet)
然後用循環sheet數據(該數據就是excel表格中的沒一個單元格的列表,使用列行命名如A1)
利用單元格cells的名字區別是哪行哪列,然後設置樣式

最後將寫完樣式的sheet數據用XLSXStyle.write、下載


<template>
  <div class="app-container">
    <el-button type="warning" icon="el-icon-download" @click="exportClick">導出</el-button>
    <vxe-table
      :cell-config="{height: 70}"
      :loading="listLoading"
      stripe
      style="width: 100%"
      size="medium"
      border
      resizable
      row-key
      highlight-current-row
      highlight-hover-row
      :height="400"
      :data="tableData"
      align="center"
    >
      <vxe-table-column type="seq" width="60" fixed="left" title="序號" />
      <vxe-table-column
        field="name"
        align="center"
        title="名字"
        min-width="130"
      />
      <vxe-table-column
        field="mobile"
        align="center"
        title="手機號碼"
        min-width="110"
      />
      <vxe-table-column
        field="price"
        align="center"
        title="金額"
        min-width="110"
      />
      <vxe-table-column
        field="team"
        align="center"
        title="所屬團隊"
        min-width="100"
      />
    </vxe-table>
  </div>
</template>

<script>
import XLSX from 'xlsx'
import XLSXStyle from 'xlsx-style'
export default {
  name: 'Test',
  components: {},
  data() {
    return {
      tableData: [
        { name: '張三', mobile: '13300000001', price: '623.00', team: '團隊一' },
        { name: '張思', mobile: '13300000002', price: '20.00', team: '團隊二' },
        { name: '張武', mobile: '13300000003', price: '90.00', team: '團隊三' },
        { name: '張柳', mobile: '13300000004', price: '54.00', team: '團隊四' }
      ],
      listLoading: false
    }
  },
  created() {
  },
  mounted() {
  },
  methods: {
    // 導出按鈕方法
    exportClick() {
      const workbook = XLSX.utils.book_new()// 創建一個空的excel文件
      const worksheet = XLSX.utils.json_to_sheet(this.tableData)// 將json數據轉成sheet格式(創建出一個sheet文件)
      XLSX.utils.book_append_sheet(workbook, worksheet)// 將sheet加進excel文件裏

      const tableData = this.tableData
      const columnHeader = {
        'name': '名字',
        'mobile': '手機號碼',
        'price': '金額',
        'team': '所屬團隊'
      } // 此處是表頭
      const dealTableLine = this.transferData(tableData, columnHeader)// 用表頭和數據換取按行形式的數據
      const sheetsList = XLSX.utils.aoa_to_sheet(dealTableLine)// 再將數據轉成sheet格式

      // 1.設置基礎框架 列寬、合併等
      sheetsList['!cols'] = [{ wch: 9 }, { wch: 20 }, { wch: 18 }, { wch: 15 }, { wch: 18 }]// 設置字段寬度;從第一列到最後
      sheetsList['!merges'] = [{ s: { c: 0, r: 0 }, e: { c: 4, r: 0 }}]// 設置表標題合併。(s:開始 e:結束)從0列,0行到4列,0行合併

      // 2.循環每一列,設置該列的樣式
      const borderstyle = { bottom: { style: 'thin', color: 'FF0000' }, right: { style: 'thin', color: 'FF0000' }}// 右+下邊線
      for (const cells in sheetsList) {
        const cells_row_no = cells.replace(/[^0-9]/ig, '')// 去掉字母只留數字:數字代表行數
        const cells_col_no = cells.replace(/[^a-zA-Z]/g, '')// 去掉數字只留字母:字母代表列
        // cells:A1 A2 A3 B1 B2...
        if (cells != '!ref' && cells != '!merges' && cells != '!cols') { // 排除幾項基礎設定
          if (cells_row_no === '1') { // 第一行 標題
            sheetsList[cells].s = {
              font: { name: '宋體', sz: 16, bold: false },
              alignment: { horizontal: 'center', vertical: 'center' },
              border: { bottom: { style: 'thin', color: 'FF0000' }}
            }
          } else if (cells_row_no === '2') { // 第二行 表頭
            sheetsList[cells].s = {
              fill: { fgColor: { rgb: 'FFFF00' }},
              font: { name: '宋體', sz: 14, bold: true },
              alignment: { horizontal: 'left', vertical: 'center' },
              border: borderstyle
            }
          } else { // 剩餘所有行
            sheetsList[cells].s = {
              font: { name: '宋體', sz: 11, bold: false },
              alignment: { horizontal: 'left', vertical: 'center' },
              border: borderstyle
            }

            if (cells_col_no == 'B') { // B列 名字
              sheetsList[cells].s = {
                font: { name: '宋體', sz: 12, color: { rgb: '0563C1' }, underline: false },
                alignment: { horizontal: 'left', vertical: 'center' },
                border: borderstyle
              }
            } else if (cells_col_no == 'D') { // D列 金額
              sheetsList[cells].s = {
                font: { name: '宋體', sz: 14, color: { rgb: 'ff0000' }, underline: true },
                alignment: { horizontal: 'left', vertical: 'center' },
                border: borderstyle
              }
            } else {}
          }
          // A列序號列設置居中
          if (cells_col_no == 'A') {
            sheetsList[cells].s.alignment.horizontal = 'center'
          }
        }
      }

      // 數據循環完畢
      workbook['SheetNames'] = ['測試sheet']
      workbook['Sheets'] = { '測試sheet': sheetsList }
      this.exportFile(this.sheet2blob(workbook), '測試導出表格.xlsx')
    },

    // 把表頭和數據整理成按行的形式
    transferData(data, columnHeader) {
      const content = []
      const otitle = '測試表格標題'
      content.push([otitle])// 1.第一行 表格標題名字

      const header = []
      for (const i in columnHeader) {
        header.push(columnHeader[i])// 生成表頭行
      }
      header.unshift('序號')
      // header: ['序號', '名字', '手機號碼', '金額', '所屬團隊']
      content.push(header)// 2.第二行 表頭行

      data.forEach((item, index) => {
        const arr = []
        for (const i in columnHeader) {
          arr.push(item[i])
        }
        arr.unshift(index + 1)
        content.push(arr)// 3.循環 依次插入數據行
      })
      return content
      /**
       * content:
       * [
       *  ["測試表格標題"],
       *  ["序號","名字","手機號碼","金額","所屬團隊"],
       *  [1,"張三","13300000001","623.00","團隊一"],
       * ]
       */
    },

    // 轉xlsx-style的download
    sheet2blob(workbook) {
      const wbout = XLSXStyle.write(workbook, {
        bookType: 'xlsx', // 要生成的文件類型
        bookSST: false, // 是否生成Shared String Table,官方解釋是,如果開啓生成速度會下降,但在低版本IOS設備上有更好的兼容性
        type: 'binary'
      })

      const blob = new Blob([s2ab(wbout)], {
        type: 'application/octet-stream'
      }) // 字符串轉ArrayBuffer

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

    // 下載文件方法
    exportFile(url, saveName) {
      if (typeof url === 'object' && url instanceof Blob) {
        url = URL.createObjectURL(url) // 創建blob地址
      }
      const aLink = document.createElement('a')
      aLink.href = url
      aLink.download = saveName || '' // HTML5新增的屬性,指定保存文件名,可以不要後綴,注意,file:///模式下不會生效
      let event
      if (window.MouseEvent) event = new MouseEvent('click')
      else {
        event = document.createEvent('MouseEvents')
        event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
      }
      aLink.dispatchEvent(event)
    }

  }
}
</script>
<style scoped>
</style>
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.