一、省流
二、安装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>