html生成pdf的jspdf和html2pdf使用
有些场景需要生成pdf文件,然而多数情况下对pdf文件的格式内容都有要求,因此研究下由html生成pdf的组件,找到了jspdf和html2pdf这两种,而html2pdf是基于jspdf的。
jspdf 2.5.1 html2canvas 1.4.1 html2pdf.js v0.9.3
先使用bootstrap5做个demo页面
查看代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>jspdf</title>
<link href="./plugins/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
<script src="./plugins/jquery/jquery-1.9.1.js"></script>
<script src="./plugins/jspdf/dist/jspdf.umd.min.js"></script>
<script src="./plugins/html2canvas.min.js"></script>
<script src="./plugins/jspdf/msyh-normal.js"></script>
<script src="./plugins/html2pdf.bundle.min.js"></script>
<script src="./plugins/jsPDF-AutoTable-master/dist/jspdf.plugin.autotable.js"></script>
<style>
body * {
font-family: "msyh";
letter-spacing: 0.01px; /*解决jspdf的英文字母间隔问题 */
}
tr {
height: 3rem;
}
</style>
</head>
<!-- body的宽度是为了适配pdf文件 -->
<body style="width: 158mm">
<div id="myExportArea" class="container pt-2">
<div style="page-break-inside: avoid">
<h1>H1标题</h1>
<h2>H2标题</h2>
<h3>H3标题</h3>
<h4>H4标题</h4>
<h5>H5标题</h5>
<h6>H6标题</h6>
</div>
<table style="border: 1px solid black; width: 100%; page-break-inside: avoid" class="table table-bordered" id="table1">
<tr class="text-center">
<th scope="col">中文</th>
<th scope="col">First</th>
<th scope="col">Last</th>
<th scope="col">Handle</th>
</tr>
<tr>
<th scope="row">1</th>
<td style="background-color: #f5da55">Mark</td>
<td>Otto</td>
<td>mdo</td>
</tr>
<tr>
<th scope="row">2</th>
<td>Jacob</td>
<td>Thornton</td>
<td>fat</td>
</tr>
<tr>
<th scope="row">3</th>
<td colspan="2">Larry the Bird</td>
<td>twitter</td>
</tr>
</table>
<div class="row g-1 mt-2" id="exportArea" style="page-break-inside: avoid">
<div class="col-6">
<div class="card">
<img src="./images/1.jpg" class="card-img-top" />
<div class="card-body">
<h5 class="card-title">明天</h5>
<p class="card-text">明天,又是新的一天。</p>
</div>
</div>
</div>
<div class="col-6">
<div class="card">
<img src="./images/1.jpg" class="card-img-top" />
<div class="card-body">
<h5 class="card-title">明天</h5>
<p class="card-text">明天,又是新的一天。</p>
</div>
</div>
</div>
</div>
<div class="row g-1 mt-2" id="exportArea" style="page-break-inside: avoid">
<div class="col-6">
<div class="card">
<img src="./images/1.jpg" class="card-img-top" />
<div class="card-body">
<h5 class="card-title">明天</h5>
<p class="card-text">明天,又是新的一天。</p>
</div>
</div>
</div>
<div class="col-6">
<div class="card">
<img src="./images/1.jpg" class="card-img-top" />
<div class="card-body">
<h5 class="card-title">明天</h5>
<p class="card-text">明天,又是新的一天。</p>
</div>
</div>
</div>
</div>
<table style="border: 1px solid black; width: 100%; page-break-inside: avoid" class="table table-bordered mt-2" id="table2">
<tr class="text-center">
<th scope="col">中文</th>
<th scope="col">First</th>
<th scope="col">Last</th>
<th scope="col">Handle</th>
</tr>
<tr>
<th scope="row">1</th>
<td style="background-color: #f5da55">Mark</td>
<td>Otto</td>
<td>mdo</td>
</tr>
<tr>
<th scope="row">2</th>
<td>Jacob</td>
<td>Thornton</td>
<td>fat</td>
</tr>
<tr>
<th scope="row">3</th>
<td colspan="2">Larry the Bird</td>
<td>twitter</td>
</tr>
</table>
<table style="border: 1px solid black; width: 100%; page-break-inside: avoid" class="table table-bordered mt-2" id="table3">
<tr class="text-center">
<th scope="col">中文</th>
<th scope="col">First</th>
<th scope="col">Last</th>
<th scope="col">Handle</th>
</tr>
<tr>
<th scope="row">1</th>
<td style="background-color: #f5da55">Mark</td>
<td>Otto</td>
<td>mdo</td>
</tr>
<tr>
<th scope="row">2</th>
<td>Jacob</td>
<td>Thornton</td>
<td>fat</td>
</tr>
<tr>
<th scope="row">3</th>
<td colspan="2">Larry the Bird</td>
<td>twitter</td>
</tr>
</table>
</div>
<div style="margin-top: 3rem">
<button type="button" class="btn btn-primary mb-2" onclick="testJsPdf('myExportArea')">jspdf downloadPdf</button>
<button type="button" class="btn btn-primary mb-2" onclick="testJsPdfAutoTable('myExportArea')">jspdf AutoTable downloadPdf</button>
<button type="button" class="btn btn-primary mb-2" onclick="testHtml2Pdf('myExportArea')">html2pdf downloadPdf</button>
<button type="button" class="btn btn-primary mb-2" onclick="testHtml2Canvas('myExportArea')">exportPdf</button>
</div>
</body>
</html>
显示如下:
下面看下html转换成pdf的css样式支持效果:
jspdf
<button type="button" class="btn btn-primary mb-2" onclick="testJsPdf('myExportArea')">jspdf downloadPdf</button>
<button type="button" class="btn btn-primary mb-2" onclick="testJsPdfAutoTable('myExportArea')">jspdf AutoTable downloadPdf</button>
<script>
function testJsPdf(domId) {
// const doc = new jspdf.jsPDF("landscape", "pt", "a4"); // 170mm宽度
const doc = new jspdf.jsPDF("portrait", "pt", "a4"); //宽度 158mm或者37.5rem
doc.setFont("msyh");
doc.html(document.getElementById(domId), {
callback: function (doc) {
const pageCount = doc.internal.getNumberOfPages();
// for (let i = pageCount; i > 1; i--) {
// doc.deletePage(i);
// }
console.log(pageCount);
// doc.save("test.pdf"); //下载pdf
window.open(doc.output("bloburl")); //预览pdf
},
});
}
function testJsPdfAutoTable(domId) {
const doc = new jspdf.jsPDF("portrait", "pt", "a4");
doc.setFont("msyh");
doc.autoTable({ html: "#table1", styles: { font: "msyh", fontStyle: "normal" }, useCss: true });
doc.autoTable({ html: "#table2", styles: { font: "msyh", fontStyle: "normal" }, useCss: true });
doc.autoTable({ html: "#table3", styles: { font: "msyh", fontStyle: "normal" }, useCss: true });
const beginY = doc.lastAutoTable.finalY;
doc.html(document.getElementById(domId), {
callback: function (doc) {
const pageCount = doc.internal.getNumberOfPages();
console.log(pageCount);
// doc.save("test.pdf"); //下载pdf
window.open(doc.output("bloburl")); //预览pdf
},
});
}
</script>
看着使用和不使用 jsPDF-AutoTable 效果差不多,css样式 page-break-inside: avoid 未生效,文本可选中。
html2pdf
<button type="button" class="btn btn-primary mb-2" onclick="testHtml2Pdf('myExportArea')">html2pdf downloadPdf</button>
<script>
function testHtml2Pdf(domId) {
const element = document.getElementById(domId);
const opt = {
margin: 0,
filename: "myfile.pdf",
image: { type: "jpeg", quality: 0.98 },
html2canvas: { dpi: 192, scale: 2, letterRendering: true },
jsPDF: { unit: "pt", format: "a4", orientation: "portrait" },
pagebreak: { mode: ["avoid-all"] },
};
html2pdf().set(opt).from(element).save();
// const worker = html2pdf();
// for (let i = 0; i < pages.length; i++) {
// console.log(pages[i]);
// worker = worker
// .set(opt)
// .from(pages[i])
// .toContainer()
// .toCanvas()
// .toPdf()
// .get("pdf")
// .then((pdf) => {
// if (i < pages.length - 1) {
// pdf.addPage();
// }
// });
// }
// worker.save();
}
</script>
css样式 page-break-inside: avoid 生效,避免了内部截断,然文本不可选中,为图片格式。
html2canvas+jspdf
<button type="button" class="btn btn-primary mb-2" onclick="testHtml2Canvas('myExportArea')">exportPdf</button>
<script>
function testHtml2Canvas(domId) {
html2canvas(document.getElementById(domId), { scale: 2 }).then((canvas) => {
const contentWidth = canvas.width;
const contentHeight = canvas.height;
//a4纸的尺寸[595,842]
const a4_width = 595;
const a4_height = 842;
//单页换算成A4纸的页面高度;
const pageHeight = (contentWidth / a4_width) * a4_height;
//未生成pdf的页面高度
let leftHeight = contentHeight;
//pdf页面偏移
let position = 0;
//html页面生成的canvas在pdf中图片的宽高
const imgWidth = a4_width;
const imgHeight = (imgWidth / contentWidth) * contentHeight;
const pageData = canvas.toDataURL("image/jpeg", 1.0);
const pdf = new jspdf.jsPDF("p", "pt", "a4");
//当内容未超过pdf一页显示的范围,无需分页
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 -= a4_height;
//避免添加空白页
if (leftHeight > 0) {
pdf.addPage();
}
}
}
let targetPage = pdf.internal.getNumberOfPages();
// pdf.save("xxxx.pdf");
window.open(pdf.output("bloburl")); //预览pdf
});
}
</script>
生成pdf为图片格式,不支持css样式 page-break-inside: avoid
分类:
javascript
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix