当画面有自定义的表格或者样式过于复杂的表格时,导出功能可以由前端实现
1. 使用的插件 : sheet.js-xlsx
文档地址:https://docs.sheetjs.com/
中文地址:https://geekdaxue.co/read/SheetJS-docs-zh/README.md
xlsx-style:https://www.npmjs.com/package/xlsx-style
2. 安装引用
安装插件-vue3
yarn add xlsx
yarn add xlsx-style-vite (有样式需求才需要安装;背景色等)
引用插件
import * as XLSX from 'xlsx';
import * as XLSX_STYLE from 'xlsx-style-vite'
3. 组件表格的导出(无样式)
以ant design vue 表格为例,只导出表格内容
<a-table :columns="columns" :dataSource="detaildata" :scroll="{ x: 'max-content',y:700 }" ></table?>
<a-button @click="exportData">导出</a-button>
<script>
//数据处理为数组
const transData=(columns, tableList)=> {
const obj = columns.reduce((acc, cur) => {
if (!acc.titles && !acc.keys) {
acc.titles = [];
acc.keys = [];
}
acc.titles.push(cur.title);
acc.keys.push(cur.dataIndex);
return acc;
}, {});
const tableBody = tableList.map((item,i) => {
return obj.keys.map((key,index) => item[key]);
});
return [ obj.titles, ...tableBody ];
}
const exportData=()=>{
const tableData = transData(
columns.value,
detaildata.value
);
// 将数据数组转换为工作表
const ws = XLSX.utils.aoa_to_sheet(tableData);
// 创建 workbook
const wb = XLSX.utils.book_new();
ws['!ref'] = `A1:AI${tableData.length}`;
//设置列宽
ws["!cols"] = [
{wpx: 120},
{wpx: 100},
{wpx: 110},
{wpx: 110},];
//合并单元格
ws['!merges'] = [{ s: { r: 0, c: 0 }, e: { r: 0, c: 1 } }]
// 将 工作表 添加到 workbook
XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');
// 将 workbook 写入文件
XLSX.writeFile(wb, 'tablename.xlsx');
}
</script>
3. 自定义表格的导出 (div拼成的表格)
比如这种前端拼成的,又附带各种样式的表格
一些常用的格式:
(1):合并单元格
(2):列宽
(3):背景色
(4):字体相关-大小粗细颜色字体等
(5):表格线,边框
详细的格式可以参考:
https://www.jianshu.com/p/869375439fee
https://www.npmjs.com/package/xlsx-style
数据处理就不写了,数据处理为数组就可以了
const toExcel=()=>{
const data = [
['左上表头','','','右上',''],
['标题1','','','',''],
['标题','测试合并','','',''],
['固定标题','123','123','',''],
['左下表头','','','右下',''],
['2021','¥28337','测试数据','北京','黑龙江'],
......
]
const worksheet = XLSX.utils.aoa_to_sheet([headers, ...data])
const workbook = XLSX.utils.book_new()
worksheet['!ref'] = `A1:AI${data.length}`
//列宽 按excel的列顺序排列,对应A列,B列, C列......
worksheet["!cols"] = [
{wpx: 200},
{wpx: 80},
{wpx: 80},
{wpx: 110},
{wpx: 110},
];
/*
合并单元格 默认合并当前格的右侧格子
{ s: { r: 0, c: 0 }, e: { r: 0, c: 1 } }
A1 与 B1 合并 内容为 A1 的内容
s:start 合并开始 e:end 合并结束
r:row 行 c:col 列
*/
worksheet['!merges'] = [
{ s: { r: 0, c: 0 }, e: { r: 0, c: 1 } },
{ s: { r: 0, c: 4 }, e: { r: 0, c: 5 } },
{ s: { r: 4, c: 0 }, e: { r: 4, c: 1 } },
......
];
//表格详细样式
for (let key in worksheet) {
if (key == '!ref' || key == '!merges' || key == '!cols' || key == '!rows') {
continue
} else {
//通过key值来选择筛选想要的设置样式的单元格
if (key.substring(1)=='1'||key.substring(1)=='5'|| key == 'A2') {
worksheet[key].s = { // 设置单元格样式
fill: { // 设置背景色
fgColor: { rgb: 'F2F3F7' },
},
font: { // 设置字体
name: '等线', // 字体名称
sz: 16, // 字体大小
bold: true, // 字体是否加粗
color:{ //字体颜色
rgb:'ed263d'
}
},
border:{ //设置边框
top: {
style: 'thin',
color:{
rgb:'e5e7eb'
}
},
bottom: {
style: 'thin',
color:{
rgb:'e5e7eb'
}
}
},
alignment: {
horizontal: 'center', // 横向(向左、向右、居中)
vertical: 'center', // 纵向(向上、向下、居中)
wrapText: true, // 设置单元格自动换行,目前仅对非合并单元格生效
indent: 0 // 设置单元格缩进
}
}
}else if(key == 'B1'){
......
}
}
}
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
const tmpDown = new Blob([
s2ab(
XLSX_STYLE.write(workbook, {
bookType: 'xlsx',
bookSST: false,
type: 'binary',
cellStyles: true,
})
),
])
downloadExcelFile(tmpDown, 'excelname' + '.xlsx')
}
/*用到的方法*/
export 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 标签下载文件
*/
export 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)
}
参考文章:https://blog.csdn.net/Cai181191/article/details/131130926