Vue 前端 实现 HTML 转 PDF 并导出(方案一:html2canvas + jspdf 前端直接实现)
Vue 前端 实现 HTML 转 PDF 并导出(方案一:html2canvas + jspdf 前端直接实现)
·
近期公司提出了一个新需求,希望将用户在前端填写的一系列数据生成一个报告给用户,报告大概有8个表格,表格涉及到分页。于是查询了资料,做出两个方案。
方案二请点击这里
方案一
html2canvas + jspdf
使用html2canvas将使用canvas将页面转为base64图片流,并插入jspdf插件中,保存并下载pdf
使用
- 安装:
npm install --save html2canvas
npm install --save jspdf
- 绘制页面,页面上一共有两个表格
<template>
<div class="table-wrapper">
<div class="tables">
<div class="pdf-dom">
<div class="title">
表 A.1 xxx汇总表
</div>
<table class="table" border="1" cellspacing="0">
<thead>
<tr>
<td>类别</td>
<td>商品</td>
<td>小计</td>
</tr>
</thead>
<tbody>
<tr>
<td>T恤</td>
<td>5</td>
<td>5</td>
</tr>
<tr>
<td>外套</td>
<td>5</td>
<td>5</td>
</tr>
<tr>
<td>羽绒服</td>
<td>5</td>
<td>5</td>
</tr>
<tr>
<td>短袖</td>
<td>5</td>
<td>5</td>
</tr>
<tr>
<td>短裤</td>
<td>5</td>
<td>5</td>
</tr>
<tr>
<td>连衣裙</td>
<td>5</td>
<td>5</td>
</tr>
<tr>
<td>半身裙</td>
<td>5</td>
<td>5</td>
</tr>
</tbody>
</table>
</div>
<div class="pdf-dom">
<div class="title">
表 A.2 xxx汇总表
</div>
<table class="table" border="1" cellspacing="0">
<thead>
<tr>
<td>类别</td>
<td>商品</td>
<td>小计</td>
</tr>
</thead>
<tbody>
<tr>
<td>T恤</td>
<td>5</td>
<td>5</td>
</tr>
<tr>
<td>外套</td>
<td>5</td>
<td>5</td>
</tr>
<tr>
<td>羽绒服</td>
<td>5</td>
<td>5</td>
</tr>
<tr>
<td>短袖</td>
<td>5</td>
<td>5</td>
</tr>
<tr>
<td>短裤</td>
<td>5</td>
<td>5</td>
</tr>
<tr>
<td>连衣裙</td>
<td>5</td>
<td>5</td>
</tr>
<tr>
<td>半身裙</td>
<td>5</td>
<td>5</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="content">
<button type="primary" @click="onExport">{{ $t('common.confirm') }}</button>
</div>
</div>
</template>
<script>
import { htmlToPdf } from '@/utils/htmlToPdf';
export default {
methods: {
async onExport() {
await htmlToPdf('pdf-dom', '报告');
},
},
};
</script>
<style lang="less" scoped>
.pdf-dom {
height: 1104px;
width: 800px;
padding: 20px;
.title {
font-size: 18px;
font-weight: 600;
margin-bottom: 10px;
text-align: center;
}
.footer {
text-align: end;
}
}
.table {
width: 100%;
border: 1px solid #999;
padding: 0;
margin: 0;
border-collapse: collapse;
th {
height: 45px;
line-height: 45px;
text-align: center;
border-bottom: 1px solid #999;
padding: 0;
margin: 0;
}
td {
height: 45px;
line-height: 45px;
text-align: center;
border-bottom: 1px solid #999;
padding: 0;
margin: 0;
}
tr:hover {
background-color: #f8f8f8;
}
}
</style>
- htmlToPdf.js
import html2Canvas from 'html2canvas';
import JsPDF from 'jspdf';
export const htmlToPdf = async (name, title) => {
const startAt = new Date();
const element = document.querySelectorAll(`.${name}`);
let count = 0;
const PDF = new JsPDF('', 'pt', 'a4');
const pageArr = [];
const opts = {
width: '840',
scale: 12, // 缩放比例,提高生成图片清晰度
useCORS: true, // 允许加载跨域的图片
allowTaint: false, // 允许图片跨域,和 useCORS 二者不可共同使用
tainttest: true, // 检测每张图片已经加载完成
logging: true, // 日志开关,发布的时候记得改成 false
};
let pdfData = '';
for await (const [index] of Array.from(element).entries()) {
const canvas = await html2Canvas(element[index], opts);
// a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
const contentWidth = canvas.width;
const contentHeight = canvas.height;
const imgWidth = 595.28;
const imgHeight = (592.28 / contentWidth) * contentHeight;
const pageData = canvas.toDataURL('image/jpeg', 1.0);
// 一页pdf显示html页面生成的canvas高度;
const pageHeight = (contentWidth / 592.28) * 841.89;
// 未生成pdf的html页面高度
const leftHeight = contentHeight;
pageArr[index] = { pageData, pageHeight, leftHeight, imgWidth, imgHeight };
if (++count === element.length) {
// 转换完毕,可进行下一步处理 pageDataArr
let counts = 0;
for (const data of pageArr) {
// 页面偏移
let position = 0;
// 转换完毕,save保存名称后浏览器会自动下载
// 当内容未超过pdf一页显示的范围,无需分页
if (data.leftHeight < data.pageHeight) {
// addImage(pageData, 'JPEG', 左,上,宽度,高度)设置
PDF.addImage(data.pageData, 'JPEG', 0, 0, data.imgWidth, data.imgHeight);
} else {
// 超过一页时,分页打印(每页高度841.89)
while (data.leftHeight > 0) {
PDF.addImage(data.pageData, 'JPEG', 0, position, data.imgWidth, data.imgHeight);
data.leftHeight -= data.pageHeight;
position -= 841.89;
if (data.leftHeight > 0) {
PDF.addPage();
}
}
}
if (++counts === pageArr.length) {
pdfData = PDF.output('datauristring');
const endAt = new Date();
PDF.save(`${title}-${new Date().getTime()}.pdf`);
console.log(`生成成功.......,时间:${(endAt.getTime() - startAt.getTime()) / 1000}s`);
} else {
// 未转换到最后一页时,pdf增加一页
PDF.addPage();
}
}
}
}
return pdfData;
};
- 生成的pdf
缺点
- 绘制页面时间很长(上图代码中的页面花费了5.386s)
- 由于导出的PDF是由图片生成的,所以PDF的文字无法进行复制
优点
简单的页面可以使用
方案二
更多推荐
已为社区贡献7条内容
所有评论(0)