Vue2实现导出Excel文件,并设置行高,宽度,合并单元格等。

一、省流

        Demo

        代码

二、安装xlsx和xlsx-style-fixedver

npm install xlsx
npm install xlsx-style-fixedver

        xlsx免费版只支持基础的生成xlsx文件,并不支持设置各种样式,不过好在有大神封装了xlsx-style这个库,可以让我们白嫖xlsx付费版的功能。

        不过现在xlsx-style这个库现在已经没有人维护了,且xlsx-style不支持修改行高,想要修改行高的话需要修改源码,所以我们现在选择xlsx-style-fixedver这个库,该库对xlsx-style进行了修复,默认支持修改行高。注意:使用xlsx-style-fixedver时必须要设置行高,不然会报错!!!

三、可能遇到的问题

        首先确定下库的版本:

1、Module not found: Error: Can't resolve 'fs'

在vue.config.js中添加如下代码

  configureWebpack: {
    externals: {
      fs: require('fs')
    },
  }

2、jszip is not a constructor

首先安装下面这个库

npm install node-polyfill-webpack-plugin

在vue.config.js中添加如下代码

const NodePolyfillPlugin = require('node-polyfill-webpack-plugin')
configureWebpack: {
  plugins: [new NodePolyfillPlugin()]
}

最终vue.config.js代码如下:

const NodePolyfillPlugin = require('node-polyfill-webpack-plugin')
module.exports = {
  publicPath: './',
  lintOnSave: false,
  configureWebpack: {
    externals: {
      fs: require('fs')
    },
    plugins: [new NodePolyfillPlugin()]
  }
}

四、封装方法

代码都有注释,且本身也比较简单,应该都是能看懂的

import * as XLSX from 'xlsx/xlsx.mjs'
import XLSXStyle from 'xlsx-style-fixedver'
/**
 * 将 String 转换成 ArrayBuffer
 * @method 类型转换
 * @param {String} [s] wordBook内容
 * @return {Array} 二进制流数组
 */
function s2ab(s) {
  let buf = null
  if (typeof ArrayBuffer !== 'undefined') {
    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
  }
  buf = new Array(s.length)
  for (let i = 0; i !== s.length; ++i) {
    // 转换成二进制流
    buf[i] = s.charCodeAt(i) & 0xFF
  }
  return buf
}

/**
 * 方案一:利用 URL.createObjectURL 下载 (以下选用)
 * 方案二:通过 file-saver 插件实现文件下载
 * @method 文件下载
 * @param {Object} [obj] 导出内容 Blob 对象
 * @param {String} [fileName] 文件名 下载是生成的文件名
 * @return {void}
 */
function saveAs(obj, fileName) {
  const aLink = document.createElement('a')
  // eslint-disable-next-line eqeqeq
  if (typeof obj == 'object' && obj instanceof Blob) {
    aLink.href = URL.createObjectURL(obj) // 创建blob地址
  }
  aLink.download = fileName
  aLink.click()
  setTimeout(function() {
    URL.revokeObjectURL(obj)
  }, 100)
}

/**
 * @method 数据导出excel
 * @param {Object} [data] 工作表数据内容
 * @param {String} [name] 导出excel文件名
 * @param {Number} [merges] 表头合并列数
 * @param {Boolean} [save] 直接下载或返回bolb文件
 */
export function exportExcel(data, name, merges, save = true) {
  return new Promise((resolve) => {
    let index = 0
    // 合并单元格 s:开始位置 e:结束位置 r:行 c:列
    const datamerges = [
      // 实际情况根据业务需求进行
      { s: { c: 0, r: 0 }, e: { c: merges, r: 0 }},
      { s: { c: 1, r: data.length + 1 }, e: { c: 3, r: data.length + 1 }}
    ]
    const worksheet1 = XLSX.utils.json_to_sheet(data, { origin: 'A2' }) // origin:指定某一行开始导入表格数据
    const itemWidth = []
    const itemHeight = []
    worksheet1['!merges'] = datamerges
    worksheet1.A1 = {
      t: 's',
      v: name
    }
    const total = `B${data.length + 2}`
    worksheet1[total] = {
      t: 's',
      v: '合计'
    }
    for (const key in worksheet1) {
      index++
      // 前两行高度为45,其后行高为25
      if (index <= 2) {
        itemHeight.push({ hch: 45 })
      } else {
        itemHeight.push({ hch: 25 })
      }
      // 所有单元格居中
      if (key !== '!cols' && key !== '!merges' && key !== '!ref' && key !== '!rows') {
        worksheet1[key].s = {
          alignment: {
            horizontal: 'center',
            vertical: 'center'
          }
        }
      }
      // 所有单元格列宽为15
      itemWidth.push({ wch: 15 })
      // A1单元格加粗居中
      if (key === 'A1') {
        worksheet1[key].s = {
          font: {
            bold: true,
            sz: 20
          },
          alignment: {
            horizontal: 'center',
            vertical: 'center'
          }
        }
      }
      if (key === total) {
        worksheet1[key].s = {
          font: {
            bold: true
          },
          alignment: {
            horizontal: 'center',
            vertical: 'center'
          }
        }
      }
      // 表头加粗居中
      if (key.replace(/[^0-9]/ig, '') === '2') {
        worksheet1[key].s = {
          font: {
            bold: true
          },
          alignment: {
            horizontal: 'center',
            vertical: 'center'
          }
        }
      }
    }
    worksheet1['!cols'] = itemWidth // 列宽
    worksheet1['!rows'] = itemHeight // 行高
    // return
    const sheetNames = Object.keys({ '总表': worksheet1 })
    const workbook = {
      SheetNames: sheetNames, // 保存的工作表名
      Sheets: { '总表': worksheet1 } // 与表名对应的表数据
    }
    // // excel的配置项
    const wopts = {
      bookType: 'xlsx', // 生成的文件类型
      bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
      type: 'binary'
    }
    // attempts to write the workbook
    // const wbout = styleXLSX.write(workbook, wopts)
    const wbout = XLSXStyle.write(workbook, wopts)
    try {
      wbout.then(res => {
        const wbBlob = new Blob([s2ab(res)], {
          type: 'application/octet-stream'
        })
        if (save) {
          saveAs(wbBlob, name + '.' + 'xlsx')
        } else {
          resolve(wbBlob)
        }
      })
    } catch (error) {
      const wbBlob = new Blob([s2ab(wbout)], {
        type: 'application/octet-stream'
      })
      if (save) {
        saveAs(wbBlob, name + '.' + 'xlsx')
      } else {
        resolve(wbBlob)
      }
    }
  })
}

使用方法:

其中testData根据自己的业务需求进行修改就行了。

<template>
  <div>
    <span class="btn" @click="createExcel">点击生成Excel</span>
  </div>
</template>

<script>
import { exportExcel } from '@/utils'
export default {
  name: 'XlsxDown',
  props: {
    msg: String
  },
  methods: {
    createExcel() {
      // 测试数据
      const testData = [
        {
          '序号': 1,
          '表头1': 1,
          '表头2': 2,
          '表头3': 3,
          '表头4': 4,
          '表头5': 5,
        },
        {
          '序号': 2,
          '表头1': 11,
          '表头2': 22,
          '表头3': 33,
          '表头4': 44,
          '表头5': 55,
        },
        {
          '序号': 3,
          '表头1': 111,
          '表头2': 222,
          '表头3': 333,
          '表头4': 444,
          '表头5': 555,
        },
      ]
      const temp = {
        '序号': testData.length + 1
      }
      temp['表头4'] = 0
      temp['表头5'] = 0
      testData.map((item) => {
        temp['表头4'] += parseFloat(item['表头4'])
        temp['表头5'] += parseFloat(item['表头5'])
      })
      testData.push(temp)
      exportExcel(testData, 'Excel下载', Object.keys(testData[0]).length - 1)
    }
  }
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
  .btn {
    border: 1px solid rgba(30,128,255,.3);
    background-color: rgba(30,128,255,.05);
    border-radius: 4px;
    cursor: pointer;
    padding: 10px;
    color: #1e80ff;
    font-size: 14px;
  }
</style>

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值