在这篇博客里,我们将学习如何利用JavaScript将HTML页面转换成PDF。
在一个项目中,我需要用JavaScript进行一些HTML到PDF的转换。
这个网站很基础。页面中有一个包含表单的div元素,我只需要从这个div生成PDF文件,并将其在新标签页中显示出来。所有操作都在客户端完成,不需要后端服务器的支持。
这里的主要任务有:
- 将 PDF 转换为 HTML。
- 在新标签页中打开 PDF。
所以呢,这里的第一条。就是把HTML转PDF,很简单,
一搜就找到了一个叫html2pdf的库。
根据其文档的描述,“html2pdf.js 通过利用 html2canvas 和 jsPDF,完全在客户端上将该网页或元素转换为可打印的 PDF 文件。”
那正是我想要的。还有网上也有很多其他的相关教程。
一切都成功了,下载的pdf却是空的。
html2pdf 会生成并返回一个空白的 PDF那有点怪。一查之下,这版有点不对劲。
用了0.9.3,问题就解决了。
CDN链接: https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.9.3/html2pdf.bundle.min.js
它显示了包含所有内容的 div(区块标签)。
JS 代码:
let 元素 = document.getElementById('div-to-print')
html2pdf().from(元素).save();
切换到全屏 退出全屏
它要么保存要么下载了 PDF 文件。
但我不需要它下载,我需要它在新标签页里打开。
使用 JavaScript 和 Blob 在新标签页中打开 PDF我们需要从pdf文件创建一个新blob,并创建一个新的URL来显示该文件。通过阅读这个问题问题,我知道了可以通过使用html2pdf提供的Promise API来获取文件而不是直接下载它,然后用它来创建一个新的blob。
我们用一个普通的文件会怎么做这件事。
const 文件输入 = document.querySelector('input[type=file]').files[0];
let 文件blob = new Blob([文件输入], { type: 'application/pdf' });
let 文件url = URL.createObjectURL(文件blob);
window.open(文件url);
全屏模式,退出全屏
与通过 html2pdf 生成的 PDF 配合使用
async function printHTML() {
// 将HTML元素转换为PDF并打开下载窗口
let worker = await html2pdf().from(element).toPdf().output('blob').then((data) => {
// 打印数据到控制台
console.log(data);
// 创建一个URL对象用于下载文件
let fileURL = URL.createObjectURL(data);
// 打开一个新的窗口以显示下载的PDF文件
window.open(fileURL);
});
}
切换到全屏模式,退出全屏
成功了。PDF不再下载,而是直接在新标签页中打开了。接着,我用CSS对div进行了样式设计。但是遇到了一个问题。
html2pdf CSS 效果未显示?我编写的 div 的 CSS 在生成 PDF 时无法加载。使用 html2pdf 时,CSS 没有生效。
我查了一下,发现外部CSS并没有被html2css加载进来。结果只打印了HTML,CSS没打印出来。
解决方法是在HTML中使用style标签写CSS,或者直接使用内联CSS。在这个讨论中也提供了一些额外的解决办法。
最后,PDF终于生成了,符合我的需求。还有一个需要注意的地方。
html2pdf 转换后的文本不可选择PDF里的文字不能选中。这可能对大多数项目来说不是必需的,但我需要这个。
html2pdf 生成 PDF 是通过 canvas 图,它一直都使用的是 html2canvas 这个工具,因此,PDF 中并没有文本,只是将 HTML 中的 canvas 图转换为 PDF。
我得换个库了。为什么不一直用我一直在用的那个库呢?
html2pdf 使用了 jsPDF。所以我尝试了 jsPDF。
doc.fromHTML(document.getElementById("div-to-print"),
22, // Margins
17,
{'width': 400},
function (a) {
// doc.save("HTML2PDF.pdf"); // 保存文件
Blob PDF = new Blob([doc.output()], { type: 'application/pdf' });
let blobUrl = URL.createObjectURL(blobPDF);
window.open(blobUrl); // 打开PDF文件
});
Correction: "let blobPDF = new Blob([doc.output()], { type: 'application/pdf' });"
should remain as the original "let blobPDF = new Blob([doc.output()], { type: 'application/pdf' });"
since "let" is a necessary keyword in JavaScript, and the variable name "blobPDF" should not be changed. The corrected version is:
doc.fromHTML(document.getElementById("div-to-print"),
22, // Margins
17,
{'width': 400},
function (a) {
// doc.save("HTML2PDF.pdf"); // 保存文件
let blobPDF = new Blob([doc.output()], { type: 'application/pdf' });
let blobUrl = URL.createObjectURL(blobPDF);
window.open(blobUrl); // 打开PDF文件
});
进入全屏,退出全屏
这里一切都好
在 jsPDF 插件中,用新标签打开 PDF 文件而不是下载文件至于在新标签页中直接打开而不是从jsPDF下载PDF文件,类似于html2pdf的情况,在回调函数中,我们可以传递doc.output()来创建blob对象。
生成的PDF是文本,而不是图像。
所以,一切顺利,我添加了CSS。但呢?
jsPDF 遇到问题,无法工作原来jsPDF和CSS不兼容。要想让它们一起用,得用html2canvas才行。而这正是html2pdf一直在做的事。
我们可以很容易地在jsPDf中设置边距。它也支持像以前一样的html属性,例如“这是p one”。但我需要使用CSS的原因是因为我尝试打印的div内部有两个子div。其中一个需要在垂直和水平方向上都居中。
接下来我搜索的是“如何只用HTML居中div里的子元素,也不用CSS?”
结果发现jsPDF里有一个文本API,它可以接受多个参数值,这使得在没有CSS的情况下轻松完成工作。
API.text = function(文本, x, y, 标志, 角度, 对齐方式); // 设置文本的显示参数
进入全屏模式 退出全屏模式
只要再多几个这样的文本,这份工作就算完成了。
结果发现它确实有效,这真是太棒了。但是不用写多个文本内容,如果我能用withHTML函数做到这一点。
通过在添加前一个块的回调函数中再添加一个 HTML 元素块,就可以实现了。
再计算几次,用计算出的值作边距,就可以完美居中了。
// 该代码段用于从HTML元素生成PDF并打开
let pageHeight = doc.internal.pageSize.height || doc.internal.pageSize.getHeight();
// 获取文档页面的高度,如果height属性不存在则尝试获取实际高度
let pageWidth = doc.internal.pageSize.width || doc.internal.pageSize.getWidth();
// 获取文档页面的宽度,如果width属性不存在则尝试获取实际宽度
let recipientBlock = document.querySelector(".div2-block");
// 选择具有类名为“div2-block”的HTML元素
let rHeight = recipientBlock.clientHeight;
// 获取recipientBlock元素的实际高度
let rWidth = recipientBlock.clientWidth;
// 获取recipientBlock元素的实际宽度
doc.fromHTML(document.querySelector(".div1-block"),
22, 17, { 'width': 200, 'height': 200 },
function (a) {
// 将具有类名为“div1-block”的HTML元素的内容转换为PDF并放置在指定位置
doc.fromHTML(document.querySelector(".div2-block"),
pageWidth / 2 - rWidth / 4,
pageHeight / 2 - rHeight / 4,
{ 'width': 200, 'height': 200 },
function (a) {
// 将具有类名为“div2-block”的HTML元素的内容转换为PDF并放置在指定位置
let blobPDF = new Blob([doc.output()], { type: 'application/pdf' });
// 创建一个新的Blob对象,包含转换后的PDF数据,并指明类型为application/pdf
let blobUrl = URL.createObjectURL(blobPDF);
// 从Blob对象创建一个新的URL
window.open(blobUrl);
// 使用新创建的URL打开一个新的窗口来查看PDF
});
});
全屏模式,退出
最后,当项目快要结束时。
最后一步是要设置最终PDF的尺寸。
在那里文档中提到,而且非常简单。
将高度和宽度以数组形式传递并指定单位。由于某些原因,“px”(像素)单位在使用时出现了问题,因此改用了“pt”单位。这样就解决了问题。
let doc = new jsPDF({orientation: 'l', unit: 'pt', format: [widthForJsPDF, heightForJsPDF]})
进入全屏,退出全屏。
这就是用JavaScript将HTML转成PDF的方法,利用JavaScript将HTML转换成PDF,这就是完成一个项目的过程。
我只是做了些谷歌搜寻。