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>

### Vue3 导出 Excel 合并单元 #### 准备环境 为了在 Vue3 项目中实现导出 Excel 功能支持合并单元,首先需要安装必要的依赖库。推荐使用 `xlsx` 和 `xlsx-style` 来处理 Excel 文件的读写操作。 ```bash npm install xlsx xlsx-style file-saver ``` 需要注意的是,在某些情况下安装 `xlsx-style` 可能会出现兼容性问题[^3]。如果遇到此类问题,建议尝试更新 Node.js 版本或寻找社区提供的解决方案。 #### 创建导出功能组件 下面是一个简单的 Vue 组件示例,展示了如何结合 Element Plus 表组件来实现出口带合并单元效果的 Excel 文件: ```html <template> <el-button @click="exportExcel">导出</el-button> <el-table :data="tableData" border style="width: 100%" :span-method="objectSpanMethod"> <!-- 表头 --> <el-table-column prop="date" label="日期"></el-table-column> <el-table-column prop="name" label="姓名"></el-table-column> <el-table-column prop="address" label="地址"></el-table-column> </el-table> </template> <script setup> import { ref } from 'vue' import XLSX from 'xlsx' import * as FileSaver from 'file-saver' const tableData = [ { date: '2016-05-02', name: '王小虎', address: '上海市普陀区金沙江路 1518 弄' }, // 更多数据... ] // 定义合逻辑 function objectSpanMethod({ row, column, rowIndex, columnIndex }) { if (columnIndex === 0) { if (rowIndex % 2 === 0) { return { rowspan: 2, colspan: 1 } } else { return { rowspan: 0, colspan: 0 } } } } async function exportExcel() { const wscols = [{ wch: 20 }, { wch: 20 }, { wch: 40 }] let data = [] for (let i = 0; i < tableData.length; ++i) { data.push([tableData[i].date, tableData[i].name, tableData[i].address]) } var wb = XLSX.utils.book_new() var ws_data = [] // 添加表头 ws_data.push(['日期', '姓名', '地址']) // 复制表主体内容至ws_data Array.prototype.push.apply(ws_data, data) // 构建工作表 var ws = XLSX.utils.aoa_to_sheet(ws_data) ws['!cols'] = wscols // 设置区域 Object.keys(tableData).forEach((key, index) => { if (index % 2 === 0 && index !== tableData.length - 1) { ws['!merges'] = ws['!merges'] ? [...ws['!merges'], { s: { r: Number(index) + 1, c: 0 }, e: { r: Number(index) + 2, c: 0 } }] : [{ s: { r: Number(index) + 1, c: 0 }, e: { r: Number(index) + 2, c: 0 } }] } }) XLSX.utils.book_append_sheet(wb, ws, "SheetJS") /* generate file and send to client */ XLSX.writeFile(wb, "sheetjs.xlsx", { bookType: 'xlsx' }) } </script> ``` 此代码片段实现了如下特性: - 使用 Element Plus 的 `<el-table>` 显示带有合并单元的数据。 - 当点击按钮时触发 `exportExcel()` 方法,该方法负责构建 Excel 工作簿将它保存为文件下载给用户。 - 对于每一的第一列(即“日期”),每隔两一次垂直方向上的合。 #### 注意事项 当涉及到复杂的样式调整或是更级的功能需求时,可能还需要深入研究 `xlsx` 文档以及探索其他插件的可能性。此外,考虑到浏览器的安全策略限制,实际应用中应当确保所有资源都来自可信源,遵循最佳实践指导原则。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值