步骤
安装和配置 xlsx 和 xlsx-style
npm install file-saver --save
npm install xlsx --save
npm install xlsx-style --save
安装启动时找不到 ./cptable 问题,需要在 vue.config.js 中 webpack 方法添加如下配置
chainWebpack(config) {
// 配置信息
config.externals({ './cptable': 'var cptable' })
}
vue页面导出
vue页面引用插件
import XLSX from 'xlsx'
import FileSaver from 'file-saver'
import XLSXSTYLE from 'xlsx-style'
给导出的table 设置id名,例如:id=“exportTable”
<el-button type="primary" @click="exportBtn">导出</el-button>
<el-table
id="exportTable"
ref="tableData"
:data="tableData"
border
stripe
style="width: 100%"
max-height="700"
highlight-current-row
>
<el-table-column prop="sno" label="学号" align="center" width="207" />
<el-table-column prop="sname" label="姓名" align="center" width="207" />
<el-table-column label="科目" align="center">
<el-table-column prop="yuwen" label="语文" align="center" />
<el-table-column prop="shuxuye" label="数学" align="center" />
<el-table-column prop="waiyu" label="外语" align="center" />
</el-table-column>
</el-table>
相关代码
// 导出excel
exportBtn() {
// 使用 this.$nextTick 是在dom元素都渲染完成之后再执行
this.$nextTick(function() {
// 设置导出的内容是否只做解析,不进行格式转换false:要解析,true:不解析
const xlsxParam = { raw: true }
// 标记1-开始
const wb = this.setExlStyle(
XLSX.utils.table_to_book(
document.querySelector('#exportTable'),
xlsxParam
)
)
// 标记1-结束
this.addRangeBorder(
wb['Sheets']['Sheet1']['!merges'],
wb['Sheets']['Sheet1']
)
// 导出excel文件名
const fileName = '学生成绩报表.xlsx'
// 注意:导出Excel, 注意这里用到的是XLSXSTYLE对象 才会有设置的样式
const wbout = XLSXSTYLE.write(wb, {
bookType: 'xlsx', // 生成的文件类型
bookSST: false,
type: 'binary'
})
try {
// 下载保存文件
FileSaver.saveAs(
new Blob([this.s2ab(wbout)], {
type: 'application/octet-stream'
}),
fileName
)
} catch (e) {
if (typeof console !== 'undefined') {
console.log(e, wbout)
}
}
return wbout
})
},
// 设置表格样式
setExlStyle(data) {
const array = Object.keys(data.Sheets.Sheet1)
array.forEach((key, index) => {
// 设置每个单元格属性
if (key.indexOf('!') < 0) {
data.Sheets.Sheet1[key].s = {
// 边框
border: {
top: { style: 'thin' },
bottom: { style: 'thin' },
left: { style: 'thin' },
right: { style: 'thin' }
},
// 字体
font: {
sz: 12,
},
// 居中
alignment: {
horizontal: 'center',
vertical: 'center',
wrapText: true
}
}
}
})
//标记2
// 列宽
data.Sheets.Sheet1['!cols'] = []
// 行宽
data.Sheets.Sheet1['!rows'] = []
// 根据列数设置每一列的列宽 这里table有5列
for (let i = 0; i < 6; i++) {
data.Sheets.Sheet1['!cols'].push({ wpx: 80, wch: 20 })
}
//设置第一列
data.Sheets.Sheet1['!cols'][0].wpx = 200
return data
},
// 文件流转换
s2ab(s) {
// 如果存在ArrayBuffer对象(es6) 最好采用该对象
if (typeof ArrayBuffer !== 'undefined') {
// 1、创建一个字节长度为s.length的内存区域
const buf = new ArrayBuffer(s.length)
// 2、创建一个指向buf的Unit8视图,开始于字节0,直到缓冲区的末尾
const view = new Uint8Array(buf)
// 3、返回指定位置的字符的Unicode编码
for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xff
return buf
} else {
const buf = new Array(s.length)
for (let i = 0; i !== s.length; ++i) buf[i] = s.charCodeAt(i) & 0xff
return buf
}
},
//表格边框:合并单元格时会丢失边框样式
addRangeBorder(range, ws) {
// s:起始位置,e:结束位置
const arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
range.forEach((item) => {
const startRowNumber = Number(item.s.r)
const startColumnNumber = Number(item.s.c)
const endColumnNumber = Number(item.e.c)
const endRowNumber = Number(item.e.r)
// 合并单元格时会丢失边框样式,例如A1->A4 此时内容在A1 而range内获取到的是从0开始的,所以开始行数要+2
for (let i = startColumnNumber; i <= endColumnNumber; i++) {
for (let j = startRowNumber + 2; j <= endRowNumber + 1; j++) {
ws[arr[i] + j] = {
s: {
border: {
top: { style: 'thin' },
left: { style: 'thin' },
bottom: { style: 'thin' },
right: { style: 'thin' }
}
}
}
}
}
})
return ws
},
vue页面效果和导出效果
问题1:导出的excel表格可以看到F列的1、2两行多出边框,解决方法
在 标记2
处增加下方代码,根据实际情况调整列名
// 导出的excel会给F这列两行有边框样式,手动去掉
var border = {
top: { style: 'none' },
bottom: { style: 'none' },
left: { style: 'thin' },
right: { style: 'none' }
}
data.Sheets.Sheet1['F1'].s = {
border: border
}
data.Sheets.Sheet1['F2'].s = {}
问题2:el-table-column 标签 有 fixed 属性
表现为:vue页面展示正常,导出excel的数据出现重复,如下
解决方法:替换 标记1
处代码
// 有fixed情况
const exportTable = document.getElementById('exportTable').cloneNode(true)
exportTable.removeChild(exportTable.querySelector('.el-table__fixed'))
// 调用改变样式的方法
const wb = this.setExlStyle(
XLSX.utils.table_to_book(
exportTable,
xlsxParam
)
)