Vue2+xlsx+xlsx-style导出带有线框和表头的表格(详细注释)
vue
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
项目地址:https://gitcode.com/gh_mirrors/vu/vue
免费下载资源
·
参考:使用Vue+xlsx+xlsx-style实现导出自定义样式的Excel文件
xlsx-style.js报错Can‘t resolve ‘./cptable‘ in ‘xxx\node_modules_xlsx_xslx-style报错-CSDN博客
"xlsx": "^0.18.5",
"xlsx-style": "^0.8.13"
"vue": "^2.5.10",
在libs里创建excel.js
import * as XLSX from 'xlsx'
import * as XLSX_STYLE from 'xlsx-style' // Vue2 + Webpack
//thList 表头,keyList 对应的字段名
/**
* 导出数据
*/
export function handelExportExcelClick(title, datas, columns) {
// 一、准备数据
const { thList, keyList } = getThList(columns);//thList:表头,keyList:对应字段名,我的columns对应的字段是label和prop,如果你是其他的,请自行修改getThList函数
const data = getList(datas, keyList)//getList函数:1、给数据添加合计行,如果不需要合计,可以在getList方法中注释掉;2、给数据中的undefined或者null字段赋值为空字符串,3、这一步骤是必须的;如果你在调用handelExportExcelClick方法时已经将数据处理好了,可以忽略getList方法,直接const data = datas;就行;
const list = getExportDataList(data, thList, keyList)
// yLength用于设置列宽
const yLength = thList.length;
// 二、新建一个工作簿
const workBook = XLSX.utils.book_new()
// 三、使用二维数组生成一个工作表
const workSheet = sheet_from_array_of_arrays(list, yLength, title)
// 四、将 "A1" 到 "M1" 的单元格合并为 "A1"
workSheet['!merges'] = [
{
s: { // s ("start"): c = 0 r = 0 -> "A1"
r: 0,
c: 0
},
e: { // e ("end"): c = 0 r = 9 -> "J1"
r: 0,
c: yLength - 1
}
}
]
// 五、设置每列的宽度(单位:px)
let wsCols = []
// 我是通过表头label的字段的值来判断来做的列宽,你也可以用其他方式来设置宽度
columns.forEach(item => {
if(item.label=='发货单位'||item.label=='收货单位'){
wsCols.push({ wch: 25 })
}
else if(item.label=='一次过磅时间'||item.label=='二次过磅时间'){
wsCols.push({ wch: 20 })
}
else if(item.label=='手机号码'){
wsCols.push({ wch: 12 })
}
else{
wsCols.push({ wch: 10 })
}
})
workSheet['!cols'] = wsCols
// 六、设置每行的高度(单位:px)
let wsRows = []
for (let i in list) {
if (i == 0) {
wsRows.push({ hpx: 100 }) // 首行标题高度为 100px
} else {
// wsRows.push({ hpx: 30 }) // 其他行高度为 30px,可以注释,表格会默认高度
}
}
workSheet['!rows'] = wsRows
// 七、设置单元格样式 对表头的样式进行修改,如果不需要可以注释
// for (let key in workSheet) {
// if (key == '!ref' || key == '!merges' || key == '!cols' || key == '!rows') {
// continue
// } else {
// // 匹配表格第一行(注意 A1 单元已合并为一个单元),设置其样式
// if (key == 'A1') {
// workSheet[key] = {
// t: 's', // 设置单元格类型(type: b Boolean, e Error, n Number, d Date, s Text, z Stub)
// v: title, // 这里设置了表头!
// // l: { Target: "https://sheetjs.com", Tooltip: "Find us @ SheetJS.com!" }, // 单元格超链接 cell hyperlink / tooltip (More Info)
// s: { // 设置单元格样式
// // fill: { // 设置背景色
// // fgColor: { rgb: 'ffffff' },
// // },
// font: { // 设置字体
// name: '等线', // 字体名称
// sz: 30, // 字体大小
// bold: true, // 字体是否加粗
// color: { rgb: '001529' }, // 文字颜色
// },
// alignment: { // 设置居中
// horizontal: 'center', // 水平(向左、向右、居中)
// vertical: 'center', // 上下(向上、向下、居中)
// wrapText: false, // 设置单元格自动换行,目前仅对非合并单元格生效
// indent: 0 // 设置单元格缩进
// },
// border: {
// top: {
// style: 'thin',
// },
// bottom: {
// style: 'thin',
// },
// left: {
// style: 'thin',
// },
// right: {
// style: 'thin',
// },
// }
// },
// }
// }
// else {
// workSheet[key].s = {
// border: {
// top: {
// style: 'thin',
// },
// bottom: {
// style: 'thin',
// },
// left: {
// style: 'thin',
// },
// right: {
// style: 'thin',
// },
// },
// fill: { // 设置背景色
// fgColor: { rgb: 'ffffff' },
// },
// font: { // 设置字体
// name: '微软雅黑', // 字体名称
// sz: 10, // 字体大小
// },
// alignment: {
// horizontal: 'center', // 水平(向左、向右、居中)
// vertical: 'center', // 上下(向上、向下、居中)
// wrapText: false, // 设置单元格自动换行,目前仅对非合并单元格生效
// indent: 0 // 设置单元格缩进
// }
// }
// }
// }
// }
// 八、在工作簿中添加工作表
XLSX.utils.book_append_sheet(workBook, workSheet, 'sheet')
// 九、使用 xlsx-style 写入文件方式,使得自定义样式生效
const tmpDown = new Blob([
s2ab(
XLSX_STYLE.write(workBook, {
bookType: 'xlsx',
bookSST: true,
type: 'binary',
cellStyles: true,
})
),
])
// 十、导出 Excel 文件
downloadExcelFile(tmpDown, title + '.xlsx')//这里使用了title为文件的名字,可以以在调用handelExportExcelClick方法时传入一个参数来代替
}
/**
* 准备数据
*/
function getExportDataList(data, thList, keyList) {
const tdList = formatJson(keyList, data) // 过滤字段以及转换数据格式,即:表格数据
tdList.unshift(thList) // 将 thList 数组添加到 tdList 数组开头,即:表格头部
tdList.unshift(['']) // 将空字符串数组添加到 tdList 数组开头,即:表格首行
const list = tdList
return list
}
/**
* 过滤字段以及转换数据格式
*/
function formatJson(filterVal, jsonData) {
return jsonData.map(v => filterVal.map(item => {
if (item === 'name') {
if (v['name'] != null && v['name'] != '') {
return v[item].split(';').join('\n')
} else {
return '-'
}
}
else {
return v[item]
}
}))
}
/**
* 使用二维数组生成一个工作表
*/
function sheet_from_array_of_arrays(data, yLength, title) {
var ws = {};
var range = {
s: {
c: 10000000,
r: 10000000
},
e: {
c: 0,
r: 0
}
}
for (var R = 0; R != data.length; ++R) {
for (var C = 0; C != data[R].length; ++C) {
if (range.s.r > R) range.s.r = R;
if (range.s.c > C) range.s.c = C;
if (range.e.r < R) range.e.r = R;
if (range.e.c < C) range.e.c = C;
var cell = {
v: data[R][C]
};
if (cell.v == null) continue;
var cell_ref = XLSX.utils.encode_cell({
c: C,
r: R
})
if (typeof cell.v === 'number') cell.t = 'n';
else if (typeof cell.v === 'boolean') cell.t = 'b';
// 这里是时间格式的处理,建议在页面中调用handelExportExcelClick方法之前,就将时间转换了
// else if (cell.v instanceof Date) {
// //console.log(cell.v)
// cell.t = 'n';
// cell.z = XLSX.SSF._table[14];
// cell.v = date_num(cell.v);
// // cell.z = 'YYYY-MM-DD'
// cell.z = 'YYYY-MM-DD HH:mm:ss'
// }
else cell.t = 's'
ws[cell_ref] = cell
}
}
if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range)
// 新增这部分:处理合并单元格 A1 到 M1 的样式
for (let c = range.s.c; c <= range.e.c; c++) {
for (let r = range.s.r; r <= range.e.r; r++) {
let cell_ref = XLSX.utils.encode_cell({ c: c, r: r });
if (r === 0 && c >= 0 && c <= yLength - 1) { // 对应合并的第一行
ws[cell_ref] = {
t: 's',
v: title,
s: {
font: {
name: '等线',
sz: 30,
bold: true,
color: { rgb: '001529' },
},
alignment: {
horizontal: 'center',
vertical: 'center',
wrapText: false,
indent: 0,
},
border: {
top: { style: 'thin' },
bottom: { style: 'thin' },
left: { style: 'thin' },
right: { style: 'thin' },
},
},
};
}
else { // 其他单元格样式
ws[cell_ref].s = {
//... 其他单元格样式 ...
border: {
top: {
style: 'thin',
},
bottom: {
style: 'thin',
},
left: {
style: 'thin',
},
right: {
style: 'thin',
},
},
fill: { // 设置背景色
fgColor: { rgb: 'ffffff' },
},
font: { // 设置字体
name: '微软雅黑', // 字体名称
sz: 10, // 字体大小
},
alignment: {
horizontal: 'center', // 水平(向左、向右、居中)
vertical: 'center', // 上下(向上、向下、居中)
wrapText: false, // 设置单元格自动换行,目前仅对非合并单元格生效
indent: 0 // 设置单元格缩进
}
};
}
}
}
return ws
}
/**
* 日期转换
*/
function date_num(v, date1904) {
if (date1904) {
v += 1462;
}
var epoch = Date.parse(v);
return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
}
/**
* 文件流转换
*/
function s2ab(s) {
if (typeof ArrayBuffer !== 'undefined') {
const 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
} else {
const buf = new Array(s.length)
for (let i = 0; i != s.length; ++i) {
buf[i] = s.charCodeAt(i) & 0xff
}
return buf
}
}
/**
* 使用 a 标签下载文件
*/
function downloadExcelFile(obj, fileName) {
const a_node = document.createElement('a')
a_node.download = fileName
if ('msSaveOrOpenBlob' in navigator) {
window.navigator.msSaveOrOpenBlob(obj, fileName)
} else {
a_node.href = URL.createObjectURL(obj)
}
a_node.click()
setTimeout(() => {
URL.revokeObjectURL(obj)
}, 2000)
}
function getThList(columns) {
let thList = []
let keyList = []
columns.forEach(item => {
thList.push(item.label)
keyList.push(item.prop)
})
return { thList, keyList }
}
function getList(data, keyList) {
// 初始化sumObj,所有key对应值设为空字符串
let sumObj = {};
keyList.forEach(key => {
sumObj[key] = '';
});
// 设置第一个item的key值为'合计'
sumObj[keyList[0]] = '合计'
// 遍历data并累加数字类型的item[key]
data.forEach(item => {
keyList.forEach(key => {
if (typeof item[key] === 'number') {
sumObj[key] = Number(sumObj[key]) + item[key];
}
});
});
// 将数据中的null和undefined替换为空字符串,如果表格数据中没有显示null和undefined,可以注释掉,如果有,这一步是必须的!
data.forEach(item => {
for (let key in item) {
if (item[key] === null || item[key] === undefined) {
item[key] = '';
}
}
});
data.push(sumObj);
return data;
}
在页面中使用:
<template>
<div>
<el-button title="导出表格" size="small" @click="exportTable('这里是导出表格的表头和文件名称')">
<i class="el-icon-tickets"></i>
</el-button>
</div>
</template>
<script>
import { handelExportExcelClick } from '@/libs/excel'
import dayjs from 'dayjs'
export default {
data() {
return {
tableData:[],//表格数据
fields: [//表格字段,我在表格中做了筛选功能,使用show字段来控制显示隐藏
{ label: '姓名', prop: 'name', show: true},
{ label: '年龄', prop: 'age', show: true},
{ label: '性别', prop: 'sex', show: true},
{ label: '地址', prop: 'address', show: true},
{ label: '电话', prop: 'phone', show: true},
{ label: '邮箱', prop: 'email', show: true},
{ label: '时间', prop: 'date', show: true},
{ label: '操作', width: 200, show: true},
],
}
},
methods: {
// 导出数据
exportTable(title){
if (this.tableData.length) {
var columns = this.fields;
// var columns = []
// this.fields.forEach((item) => {
// if(item.show && item.label !== '操作'){
// columns.push({
// label: item.label,
// prop: item.prop,
// })
// }
// })
var data = JSON.parse(JSON.stringify(this.tableData))
// data.forEach(item => {
// item.weOneWeighDate=dayjs(item.weOneWeighDate).format('YYYY-MM-DD HH:mm:ss')
// item.weTwoWeighDate=dayjs(item.weTwoWeighDate).format('YYYY-MM-DD HH:mm:ss')
// })
// 总之,在调用handelExportExcelClick之前,将数据需要过滤的字段过滤了好了再调用
handelExportExcelClick(title, data, columns)
} else {
this.$message.info('表格数据不能为空!')
}
},
}
}
</script>
效果参考:
GitHub 加速计划 / vu / vue
207.54 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5
* chore: fix link broken
Signed-off-by: snoppy <michaleli@foxmail.com>
* Update packages/template-compiler/README.md [skip ci]
---------
Signed-off-by: snoppy <michaleli@foxmail.com>
Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891
Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
更多推荐
已为社区贡献1条内容
所有评论(0)