1. 导出excel
1.1 Vue2中使用
基础使用
- 首先安装
js-xlsx
库,使用这个库可以完成一些基本的excel导出,如需导出带样式的excel,则需要使用另外一个库,后面会讲到。 - 执行如下命令
js
npm install --save xlsx
- 在untils文件夹下,新建ecxel.js
js
const XLSX = require("xlsx"); //使用import有的属性无法找到
export function exportExcel(filename, data) {
let exc = XLSX.utils.book_new(); // 初始化一个excel文件
let exc_data = XLSX.utils.aoa_to_sheet(data); // 传入数据 , 到excel
// 将文档插入文件并定义名称
XLSX.utils.book_append_sheet(exc, exc_data, filename);
// 执行下载
XLSX.writeFile(exc, filename + '.xlsx');
}
- 使用如下
- 表格数据结构
- 数据结构为一个二维数组,从上到下就是表格每一行的内容,数据层可以用循环把数据给push进去
excel_data
数据可以是前端用已有的数据处理得到,如果前端数据处理太麻烦(下面会讲一些处理方法),直接扔给后端。
1.2 Vue3 中使用
1.在utils
文件夹下新建ecxel.js
文件
js
import * as XLSX from 'xlsx'
export function exportExcel(filename,data) {
let exc = XLSX.utils.book_new();
let exc_data = XLSX.utils.aoa_to_sheet(data);
XLSX.utils.book_append_sheet(exc, exc_data, filename);
XLSX.writeFile(exc, filename + 'xlsx');
}
- 使用
js
<template>
<button @click="download">下载表格</button>
</template>
<script setup>
import { exportExcel } from "./excelConfig"
const exc_data = [['第一列', '第二列' ,'第三列'],
['aa', 'bb' ,'cc'],
['dd', 'ee' ,'ff']];
function download() { exportExcel('vue3导出的表格',this.exc_data) }
</script>
1.3 基础excel表格的导出
在until文件目录下新建excel.js,封装导出函数,更加灵活多变,不必自己去处理数组里面的每一项数据。
js
let XLSX = require('xlsx');
/**
* 导出Excel的处理函数
* @param {Array} headers 需要导出的列 示例:[{key: 'date', title: '日期'}, {key: 'name', title: '名称'}]
* @param {Array} data 导出的数据 示例:[{date: '2023-05-31', name: 'megen.huang'}, {date: 'name', name: '姓名'}]
* @param {String} fileName 文件的名称 示例:'导出结果.xlsx'
* */
function ExportExcelTwo (headers, data, fileName = '导出结果.xlsx') {
// 获取标题属性名称
const excel_headers_key = headers.map(rowItem => rowItem.key)
// 获取标题名称
const excel_headers_title = headers.map(rowItem => rowItem.title)
console.log(excel_headers_title);
// 数据转换
var excel_data = data.map(rowItem => {
var arr = [];
excel_headers_key.forEach(colItem => {
arr.push(rowItem[colItem])
})
return (arr);
})
// 将标题添加到第一行
excel_data.unshift(excel_headers_title)
const worksheet = XLSX.utils.aoa_to_sheet(excel_data)
const workbook = XLSX.utils.book_new()
// 将数据添加到工作薄
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
// 导出 Excel
XLSX.writeFile(workbook, fileName)
}
export default ExportExcelTwo
举个例子:
- 现在需要导出下面这table表的excel表格
2. 这个表格的数据格式如图所示:
3. 对数据进行分析,根据excel导出数据要为一个数组,数组里面的每一项都为数组的格式。现在后端的数据,显然不符合要求,所以需要前端对数据进行处理。
4. 导出结果
1.4 导出带样式的表格,如单元格合并,设置宽度,字体大小等
前提是安装xlsx,已经可以导出普通的excel
js
npm install --save xlsx file-saver
然后需要安装
js
npm install xlsx-js-style
举个例子:合并单元格
先看导出结果:
js
import XLSX from "xlsx-js-style";
js
exportExcel () {
// 需要导出的数据
let excelData = [
['幼儿园课表', null, null, null], // 标题
['序号', '课程名称', '教师名称', '上课地点'], // 表头
['1', '体育', '大头老师', '操场']
]
let aoa = excelData;
var sheet = XLSX.utils.json_to_sheet(aoa);
// 设置标题行单元格合并
// s即start, e即end, r即row, c即column
let mergerarr = [
// 第一行0的3列进行合并
{ s: { r: 0, c: 0 }, e: { r: 0, c: 3 } },
];
sheet['!merges'] = mergerarr;
const filename = `交接班审阅日志.xlsx`
// Excel第一个sheet的名称
const ws_name = 'Sheet1'
const wb = XLSX.utils.book_new()
const ws = XLSX.utils.json_to_sheet(aoa, {
skipHeader: true,
})
// 设置宽度
ws["!cols"] = [
{ wpx: 100, },
{ wpx: 120, },
{ wpx: 120, },
{ wpx: 100, },
];
ws['!merges'] = sheet['!merges']
XLSX.utils.book_append_sheet(wb, ws, ws_name) // 将数据添加到工作薄
XLSX.writeFile(wb, filename) // 导出Excel
},
如果需要导出下面动态数据的表格,那么可以自己设置一个标记,去记录每一行的需要设置的单元格样式。
下面代码思路可以供参考:
PS:数据叫后端处理,尽量不在前端处理一堆数据,不处理,直接叼他
js
handleExcel () {
// 时间
let list = [];//处理数据存放的数组
let mergerarr = [
{ s: { r: 0, c: 0 }, e: { r: 0, c: 9 } },
{ s: { r: 1, c: 0 }, e: { r: 1, c: 2 } },
{ s: { r: 1, c: 3 }, e: { r: 1, c: 6 } },
{ s: { r: 1, c: 7 }, e: { r: 1, c: 9 } },
{ s: { r: 2, c: 0 }, e: { r: 2, c: 9 } },
];
let tagindex = 2;
let arr = [];
arr.push(`交班日期:${this.viewData.WorkGiveDateTimeString}`, null, null);
arr.push(`时间段:${this.viewData.WorkGiveTimePar.split('-')[0]}到次日${this.viewData.WorkGiveTimePar.split('-')[1]}`, null, null, null);
arr.push(`交班类型:${this.viewData.WorkTypeTag === 1 ? '白班' : '夜班'}`, null, null);
list.push(arr);
let arr2 = [];
arr2.push('一、接班情况');
for (let i = 1; i < 10; i++) {
arr2.push(null);
}
list.push(arr2);
// 接班情况
// 第四五行
this.contentData.forEach((el) => {
tagindex++;
mergerarr.push({ s: { r: tagindex, c: 0 }, e: { r: tagindex, c: 9 } });
let tagarr = [];
tagarr.push(el);
for (let i = 1; i < 10; i++) {
tagarr.push(null)
}
list.push(tagarr);
});
// 本班工作情况
let arr5 = [];
arr5.push('二、本班工作情况');
for (let i = 1; i < 10; i++) {
arr5.push(null)
};
// 第六行
tagindex++;
mergerarr.push(
{ s: { r: tagindex, c: 0 }, e: { r: tagindex, c: 9 } }
)
list.push(arr5);
const headers = [
{ key: 'indexTag', title: '序号' },
{ key: 'OperationTickSerial', title: '流水号' },
{ key: 'OTStartDateTimeStr', title: '开始时间' },
{ key: 'aresName', title: '装置/区域' },
{ key: 'EquipTagNumber', title: '位号' },
{ key: 'WorkContent', title: '作业内容' },
{ key: 'MalfTypeName', title: '故障类型' },
{ key: 'WorkEndFeedback', title: '处理结果/反馈' },
{ key: 'WorkHandlePerson', title: '处理人' },
{ key: 'IsOperationTickText', title: '是否完成' },
]
// 获取标题属性名称
const excel_headers_key = headers.map(rowItem => rowItem.key)
// 获取标题名称
const excel_headers_title = headers.map(rowItem => rowItem.title)
// 数据转换
let data = this.viewData.OperationTickets;
var excel_data = data.map(rowItem => {
var arr = [];
excel_headers_key.forEach(colItem => {
arr.push(rowItem[colItem])
})
return (arr);
})
// 将标题添加到第一行
excel_data.unshift(excel_headers_title)
// 第七八行
excel_data.forEach((el, index) => {
tagindex++;
list.push(el);
})
// 本班工作情况
let arr6 = [];
arr6.push('二、交班情况');
for (let i = 1; i < 10; i++) {
arr6.push(null)
};
tagindex++;
mergerarr.push({ s: { r: tagindex, c: 0 }, e: { r: tagindex, c: 9 } });
list.push(arr6);
// 交班情况
this.contentData2.forEach((el, index) => {
tagindex++;
// 第九,十行
mergerarr.push({ s: { r: tagindex, c: 0 }, e: { r: tagindex, c: 9 } });
let tagarr = [];
tagarr.push(el);
for (let i = 1; i < 10; i++) {
tagarr.push(null)
};
list.push(tagarr)
})
let arr10 = [];
arr10.push(`交班人员:${this.viewData.WorkGivePerson}`, null, null,);
arr10.push(`接班人员:${this.viewData.WorkCatchPerson}`, null, null, null);
arr10.push(`审阅人:${this.viewData.ApprovalPerson === null ? '' : this.viewData.ApprovalPerson}`, null, null);
list.push(arr10);
tagindex++;
// 第十一行
mergerarr.push(
{ s: { r: tagindex, c: 0 }, e: { r: tagindex, c: 2 } },
{ s: { r: tagindex, c: 3 }, e: { r: tagindex, c: 6 } },
{ s: { r: tagindex, c: 7 }, e: { r: tagindex, c: 9 } },
);
let classesName = `${this.viewData.ClassesName}交接班审阅日志`;
let arr11 = [];
arr11.push(classesName);
for (let i = 1; i < 10; i++) {
arr11.push(null)
};
list.unshift(arr11);
this.listexcel = list;
this.mergerarr = mergerarr;
},
exportTable () {
//数据处理函数
this.handleExcel()
//单元格处理
let aoa = this.listexcel;
var sheet = XLSX.utils.json_to_sheet(aoa);
// 设置标题行单元格合并
// s即start, e即end, r即row, c即column
// 合并从--0行0列开始,到0行3列
sheet['!merges'] = this.mergerarr;
const filename = `${this.viewData.ClassesName} ${this.viewData.WorkGiveDateTimeString}交接班审阅日志.xlsx`
// Excel第一个sheet的名称
const ws_name = 'Sheet1'
const wb = XLSX.utils.book_new()
const ws = XLSX.utils.json_to_sheet(aoa, {
skipHeader: true,
})
// 设置宽度
ws["!cols"] = [
{ wpx: 100, },
{ wpx: 120, },
{ wpx: 120, },
{ wpx: 100, },
{ wpx: 100, },
{ wpx: 100, },
{ wpx: 100, },
{ wpx: 100, },
{ wpx: 100, },
{ wpx: 100, },
];
ws['!merges'] = sheet['!merges']
XLSX.utils.book_append_sheet(wb, ws, ws_name) // 将数据添加到工作薄
XLSX.writeFile(wb, filename) // 导出Excel
},
2 .excel 导出综合案例(如果其他的看不明白,直接看这个)
最终结果: 如果把这个弄懂,相信可以解决绝大部分的需求!!!
js
<template>
<div class="home">
<el-button type="primary" @click="export">excel导出</el-button>
</div>
</template>
<script>
import XLSX from "xlsx-js-style";
export default {
name: 'HomeView',
components: {
},
data () {
return {
}
},
methods: {
export () {
let excelData = [
['幼儿园课表', null, null, null], // 标题
['序号', '课程名称', '教师名称', '上课地点'], // 表头
['1', '体育', '大头老师', '操场'],
['2', '体育', '大头老师', '操场'],
['3', '化学', '李老师', '操场'],
['4', '化学', '李老师', '操场'],
];
/*
电子表格软件通常需要至少一个工作表,并强制执行 用户界面中的要求。例如,如果删除了最后一个工作表 在程序中,Apple Numbers 将自动创建一个新的空白表。
SheetJS 写入函数强制执行此要求。 它们在尝试导出空工作簿时会引发错误。
*/
const wb = XLSX.utils.book_new();//创建新工作簿
const ws = XLSX.utils.aoa_to_sheet(excelData);//aoa_to_sheet将 JS 数据数组的数组转换为工作表。
let mergerarr = [
// 第一行的 0到3列进行合并
{ s: { r: 0, c: 0 }, e: { r: 0, c: 3 } },
// 将第单列的第五行第六行进行合并
{ s: { r: 4, c: 2 }, e: { r: 5, c: 2 } },
];
// 设置合并的单元格
ws['!merges'] = mergerarr;
// 设置宽度
// !cols 设置列宽
// cols 为一个对象数组,依次表示每一列的宽度。
ws["!cols"] = [
{ wpx: 200, },
{ wpx: 120, },
{ wpx: 220, },
{ wpx: 200, },
{ wpx: 200, },
];
// !rows 设置行高
// rows 为一个对象数组,依次表示每一行的高度
const rows = [
{ hpx: 20 },
{ hpx: 16 },
{ hpx: 18 },
{ hpx: 28 },
{ hpx: 20 },
]
ws['!rows'] = rows; // 添加到sheet中
let borderAll = { //单元格外侧框线
top: {
style: 'thin',//BORDER_STYLE 是用来设置边框样式的一个字符串,
},
bottom: {
style: 'thin'
},
left: {
style: 'thin'
},
right: {
style: 'thin'
}
};
// 设置每一个单元格
for (let key in ws) {
if (ws[key] instanceof Object) {
if (key === 'B2') {//给B2这个单元格单独设置样式和背景颜色
ws[key].s = {
border: borderAll,
alignment: {
horizontal: 'center', //水平居中对齐
vertical: 'center',//垂直居中
wrapText: 1,//自动换行
},
font: {
sz: 12,//单元格中字体的样式与颜色设置
color: {
rgb: 'FF0187FA'
}
},
bold: false,//是否加粗
numFmt: 0,
// fill 颜色填充属性
fill: {
fgColor: { rgb: '87CEEB' },
},
}
} else {
ws[key].s = {
border: borderAll,
alignment: {
horizontal: 'center', //水平居中对齐
vertical: 'center',//垂直居中
wrapText: 1,//自动换行
},
font: {
sz: 12,//单元格中字体的样式与颜色设置
color: {
rgb: 'FF0187FA'
}
},
bold: false,//是否加粗
numFmt: 0,
// fill 颜色填充属性
fill: {
fgColor: { rgb: 'FFFFFF' },
},
}
}
}
};
XLSX.utils.book_append_sheet(wb, ws, "readme demo");//将上面创建好的ws页添加到wb工作簿中表格内名字为readmedemo
XLSX.writeFile(wb, "xlsx-js-style-demo.xlsx");////调用导出api
},
},
created () { }
}
</script>
<style lang="less" scoped>
</style>
3. 导出PDF
导出pdf简单多了~
1.安装两个库
js
npm install html2canvas
js
npm install jspdf
- 在
utils
文件夹下新建html2pdf.js
文件
js
import html2canvas from 'html2canvas';
import jsPDF from 'jspdf'
export const htmlToPDF = async (htmlId, title = "报表", bgColor = "#fff") => {
let pdfDom = document.getElementById(htmlId)
pdfDom.style.padding = '0 10px !important'
const A4Width = 595.28;
const A4Height = 841.89;
let canvas = await html2canvas(pdfDom, {
scale: 2,
useCORS: true,
backgroundColor: bgColor,
});
let pageHeight = (canvas.width / A4Width) * A4Height;
let leftHeight = canvas.height;
let position = 0;
let imgWidth = A4Width;
let imgHeight = (A4Width / canvas.width) * canvas.height;
/*
根据自身业务需求 是否在此处键入下方水印代码
*/
//添加水印
const ctx = canvas.getContext('2d');
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.rotate((20 * Math.PI) / 180);
ctx.font = '20px Microsoft Yahei';
ctx.fillStyle = 'rgba(184, 184, 184, 0.8)';
for (let i = canvas.width * -1; i < canvas.width; i += 240) {
for (let j = canvas.height * -1; j < canvas.height; j += 200) {
// 填充文字,x 间距, y 间距
ctx.fillText('水印名33', i, j);
}
}
let pageData = canvas.toDataURL("image/jpeg", 1.0);
let PDF = new jsPDF("p", 'pt', 'a4');
if (leftHeight < pageHeight) {
PDF.addImage(pageData, "JPEG", 0, 0, imgWidth, imgHeight);
} else {
while (leftHeight > 0) {
PDF.addImage(pageData, "JPEG", 0, position, imgWidth, imgHeight);
leftHeight -= pageHeight;
position -= A4Height;
if (leftHeight > 0) PDF.addPage();
}
}
PDF.save(title + ".pdf");
}
- 使用
导出结果:
参考链接:
xlsx-style ./cptable' 报错解决办法 - 龙果果 - 博客园
ps: 如果你觉得 xlsx-style 的功能还不够全面,不能实现你需求,这里再推荐一个项目 ExcelJS,这个项目的功能更加全面,而且项目也还在维护,可以试试看能否满足需求。