vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue导出Excel

Vue纯前端实现导出Excel并修改样式

作者:会说法语的猪

这篇文章主要为大家详细介绍了Vue如何利用xlsx-style库实现导出Excel并修改样式的功能,文中的示例代码讲解详细,有需要的可以参考下

之前写过一篇前端导出:Vue实现导出功能(无后端配合) ,但是当时没考虑到样式的问题,后来要求导出的Excel单元格的样式也需要调整,尤其是宽度,第一想到的就是xlsx-style这个包,之前也没用过,这次用一下试着调一下宽度等样式,刚安装上就嘎嘎报错~~~,下面就介绍一下该库是使用,踩坑解决...

首先安装: 

npm i file-saver -S
npm i xlsx -S
npm i xlsx-style -S

然后引入 

import * as XLSX from 'xlsx'
import FileSaver from 'file-saver'
import XLSXS from 'xlsx-style'

如果仅仅是为了导出,不修改样式,也就是不引入 xlsx-style 这个库 是没有问题的,但是引入了 xlsx-style之后,直接报错,项目直接跑不起来,首先报错如下: 

1. Module not found: Error: Can't resolve './cptable' 

解决: 

只需在vue.config.js中添加如下 

configureWebpack: {
  // 解决 Module not found: Error: Can't resolve './cptable' 
  externals: {
    './cptable': 'var cptable'
  }
}

接着还有错,

2. Module not found: Error: Can't resolve 'fs' 

解决: 

接着在vue.config.js中添加 

configureWebpack: {
  // 解决 Module not found: Error: Can't resolve './cptable'
  externals: {
    './cptable': 'var cptable'
  },
  // 解决 Module not found: Error: Can't resolve 'fs' 
  resolve: {
    fallback: {
      fs: false
    }
  }
}

再重新跑一下,哎呦呵,跑起来了,但是给出了个警告 

它让我们安装一下 crypto-browserify 这个东东,再配置一下, 应该就可以避免了吧,唉,我这里暂时没管它, 毕竟项目跑起来了,项目和人有一个能跑的就可以啦,哈哈哈哈哈哈哈哈哈哈哈...有时间再看下吧。。

当我们跑起来之后,然后使用的时候,就得使用xlsx-style中的write方法了,但是使用的时候浏览器控制台还是报错了,如下:

这个时候就得去修改源码了,位置在 node_modules/xlsx-style/xlsx.js中1339行的位置处: 

if(typeof jszip === 'undefined') jszip = require('./js'+'zip').JSZip;

修改为:

if(typeof jszip === 'undefined') jszip = require('./jszip.js');

但是我们这样只是修改我们自己的本地,下次再装依赖的时候还得重新去改,不可能每次都去这改,显然是行不通的,这时候我们就可以在package.json中scripts中添加一个脚本,有个 postinstall  钩子,在我们执行完npm install后会执行postinstall对应的脚本,所以我们可以在这里做处理。

首先我们在项目根目录下新建 lib/xlsx-style/xlsx.js,然后将node_modules/xlsx-style/xlsx.js拷贝过来一份,我们修改 lib/xlsx-style/xlsx.js 中的代码,将1339行修改掉,然后在scripts中添加postinstall

"scripts": {
  "serve": "vue-cli-service serve",
  "build": "vue-cli-service build",
  "lint": "vue-cli-service lint",
  "postinstall": "node install-xlsx-style-xlsx.js"
},

然后在根目录下新建 install-xlsx-style-xlsx.js 

const path = require('path')
const fs = require('fs')
 
const xlsxStyleModulesPath = path.join(__dirname, 'node_modules/xlsx-style/xlsx.js')
const xlsxStyleLibPath = path.join(__dirname, 'lib/xlsx-style/xlsx.js')
 
fs.writeFileSync(xlsxStyleModulesPath, fs.readFileSync(xlsxStyleLibPath))

这样就可以了,之后再安装依赖的时候就会自动替换掉node_modules/xlsx-style/xlsx.js。

key简介
v原始值(有关更多信息,请参见“数据类型”部分)
w格式化文本
t单元格类型:b布尔值,n数字,e错误,s字符串,d日期
f单元格公式
r富文本编码
h富文本格式的HTML呈现
c与单元格相关的评论
z与单元格关联的数字格式字符串
l单元超链接对象(Target含链接,tooltip工具提示)
s单元格的样式/主题

接下来就是方法的封装:

闲话不多说了,直接上代码: 

1.  这个是我们只需要把要打印的表格dom和下载的文件名称(name.xlsx)传入即可

但是这个只能打印当前的数据  

import * as XLSX from 'xlsx'
import FileSaver from 'file-saver'
import XLSXS from 'xlsx-style'
 
export default function(dom, fileName) {
  let tableDom = dom.cloneNode(true)
  let elTableFixedRight = tableDom.querySelector(".el-table__fixed-right")
  let elTableFixed = tableDom.querySelector(".el-table__fixed")
  if(elTableFixedRight) tableDom.removeChild(elTableFixedRight);
  if(elTableFixed) tableDom.removeChild(elTableFixed);
  let wb = XLSX.utils.table_to_book(tableDom, { raw: true, sheet: '运行日志表' })
  setExcelStyle(wb['Sheets']['运行日志表']) // 设置样式
  let wbout = XLSXS.write(wb, {  // 使用 xlsx-style 中的write方法
    bookType: 'xlsx',
    bookSST: false,
    type: 'binary'
  })
  try {
    FileSaver.saveAs( new Blob([s2ab(wbout)], { type: "application/octet-stream" }), fileName);
  } catch(e) {
    console.error(e, wbout, '----->>>')
  }
}
 
// 设置导出Excel样式 这里主要是关注单元格宽度
function setExcelStyle(data) {
  let borderAll = {
    //单元格外侧框线
    top: {
      style: "thin",
    },
    bottom: {
      style: "thin",
    },
    left: {
      style: "thin",
    },
    right: {
      style: "thin",
    },
  }
  data['!cols'] = []
  for(let key in data) {
    if(data[key].constructor === Object) {
      data[key].s = {
        // border: borderAll,  // 边框
        alignment: {
          horizontal: "center", //水平居中对齐
          vertical: "center", // 垂直居中
        },
        font: {
          sz: 11,
        },
        bold: true,
        numFmt: 0
      }
      data["!cols"].push({ wpx: 160 }); // 单元格宽度
    }
  }
}
 
 
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
}
 
/**
 * 根据dom导出多个Sheet页
 * 按需使用
 */
export class ExcelMultipleSheet {
  #book
  constructor() {
    this.#book = XLSX.utils.book_new()
  }
 
  append(dom, sheetname) {
    let sheet = XLSX.utils.table_to_sheet(dom)
    XLSX.utils.book_append_sheet(this.#book, sheet, sheetname)
    this.#editStyle(this.#book['Sheets'][sheetname])
  }
 
  download(filename = 'WFT.xlsx') {
    let wbout = XLSXS.write(this.#book, {
      bookType: 'xlsx',
      bookSST: false,
      type: 'binary'
    })
    try {
      FileSaver.saveAs(new Blob([this.#s2ab(wbout)], { type: "application/octet-stream" }), filename);
    } catch(e) {
      console.error(e, wbout, '----->>>')
    }
  }
 
  #editStyle(data) {
    data["!cols"] = []
    for(let key in data) {
      if(data.hasOwnProperty(key)) {
        if(data[key].constructor === Object) {
          data[key].s = {
            alignment: { horizontal: "center", vertical: "center" },
            font: { sz: 11, },
            bold: true,
            numFmt: 0
          }
          data["!cols"].push({ wpx: 160 }); // 单元格宽度
        }
      }
    }
  }
 
  #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
  }
}

2. 这个是我们可以自定义导出数据(一般表格会分页展示数据,如果按照上面的方式 只会导出当前页的,如果想导出所有数据 就使用该方法)传入数据list和一个导出的文件名

我们要遍历传入的list,所以里面的字段还需要根据自己的去修改一下

// 导出Excel
export function exportExcel(tableList, fileName) {
  let tableData = [['故障报警', '设备名称', '故障内容', '系统', '状态', '开始时间', '结束时间']]
  tableList.forEach(item => {
    tableData.push([ item.alarm, item.equipname, item.point, item.system, item.status, item.starttime, item.endtime ])
  })
  let ws = XLSX.utils.aoa_to_sheet(tableData)
  setExcelStyle(ws) // 设置样式
  let wb = XLSX.utils.book_new()
  XLSX.utils.book_append_sheet(wb, ws)
  let wbout = XLSXS.write(wb, {
    bookType: 'xlsx',
    bookSST: false,
    type: 'binary'
  })
  try {
    FileSaver.saveAs( new Blob([s2ab(wbout)], { type: "application/octet-stream" }), fileName);
  } catch(e) {
    console.error(e, wbout, '----->>>')
  }
}
 
// 设置导出Excel样式 这里主要是关注单元格宽度
function setExcelStyle(data) {
  let borderAll = {
    //单元格外侧框线
    top: {
      style: "thin",
    },
    bottom: {
      style: "thin",
    },
    left: {
      style: "thin",
    },
    right: {
      style: "thin",
    },
  }
  data['!cols'] = []
  for(let key in data) {
    if(data[key].constructor === Object) {
      data[key].s = {
        // border: borderAll,  // 边框
        alignment: {
          horizontal: "center", //水平居中对齐
          vertical: "center", // 垂直居中
        },
        font: {
          sz: 11,
        },
        bold: true,
        numFmt: 0
      }
      data["!cols"].push({ wpx: 180 }); // 单元格宽度
    }
  }
}
 
 
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
}

到此这篇关于Vue纯前端实现导出Excel并修改样式的文章就介绍到这了,更多相关Vue导出Excel内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文