最近在做項目時有這么一個需求,需要將當前html頁面導出pdf到本地。由于之前是做過類似的功能的借助了兩個插件分別是html2canvas.js和pdf.js,本以為是非常順利就能完成的,實際在使用過程中也還是出現(xiàn)了問題。
寫這篇文章也是記錄下在集成過程中遇到的問題和如何解決這些問題的。
首先導入這兩個插件:
<script src="https://cdn.bootcss.com/html2canvas/0.5.0-beta4/html2canvas.js"></script>
<script src="https://cdn.bootcss.com/jspdf/1.3.4/jspdf.debug.js"></script>
其次是導出代碼:
html部分:
<div id="rightMain">
<button onclick="exportHtml('rightMain');">導出HTM為pdf</button>
<div style="font-size: 20px;color:red">55555</div>
<div style="padding: 20px;background:#17c5b3;">0000001</div>
<div id="v2">
<table border="1">
<tr>
<th>Month</th>
<th>Savings</th>
</tr>
<tr>
<td>January</td>
<td>$100</td>
</tr>
<tr>
<th>Month</th>
<th>Savings</th>
</tr>
<tr>
<td>January</td>
<td>$100</td>
</tr>
</table>
<div>99999</div>
<div>78787</div>
...
</div>
js部分:
function exportHtml(id) {
//下載pdf方法
let demo = document.getElementById(id);
demo.style.overflow = 'visible';
html2canvas(demo, {
allowTaint: true, //允許跨域
height: document.getElementById(id).scrollHeight, //
width: document.getElementById(id).scrollWidth, //為了使橫向滾動條的內(nèi)容全部展示,這里必須指定
background: "#FFFFFF", //如果指定的div沒有設置背景色會默認成黑色
dpi: 300,
useCORS: true, //允許canvas畫布內(nèi) 可以跨域請求外部鏈接圖片, 允許跨域請求。
// scale: window.devicePixelRatio,
onrendered: function (canvas) {
var contentWidth = canvas.width;
var contentHeight = canvas.height;
//一頁pdf顯示html頁面生成的canvas高度;
var pageHeight = contentWidth / 592.28 * 841.89;
//未生成pdf的html頁面高度
var leftHeight = contentHeight;
//pdf頁面偏移
var position = 0;
//html頁面生成的canvas在pdf中圖片的寬高(a4紙的尺寸[595.28,841.89])
var imgWidth = 595.28;
var imgHeight = 592.28 / contentWidth * contentHeight;
var pageData = canvas.toDataURL('image/jpeg', 1.0);
var pdf = new jsPDF('', 'pt', 'a4');
//有兩個高度需要區(qū)分,一個是html頁面的實際高度,和生成pdf的頁面高度(841.89)
//當內(nèi)容未超過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 -= 841.89;
//避免添加空白頁
if (leftHeight > 0) {
pdf.addPage();
}
}
}
pdf.save('測試.pdf');
}
})
demo.style.overflow = 'auto';
}
其實到這里基本上就完成了可以正常導出。但是導出后發(fā)現(xiàn)并沒有邊距,和正常的pdf看起來還是有差距的。
比如導出來的截圖示例:

image.png
整體看起來還是有點突兀的,所以繼續(xù)優(yōu)化下:
function exportHtml(id) {
//下載pdf方法
let demo = document.getElementById(id);
demo.style.overflow = 'visible';
html2canvas(demo, {
allowTaint: true, //允許跨域
height: document.getElementById(id).scrollHeight, //
width: document.getElementById(id).scrollWidth, //為了使橫向滾動條的內(nèi)容全部展示,這里必須指定
background: "#FFFFFF", //如果指定的div沒有設置背景色會默認成黑色
dpi: 300,
useCORS: true, //允許canvas畫布內(nèi) 可以跨域請求外部鏈接圖片, 允許跨域請求。
// scale: window.devicePixelRatio,
onrendered: function (canvas) {
let pdf = new jsPDF('p', 'mm', 'a4'); //A4紙,縱向
let ctx = canvas.getContext('2d'),
a4w = 190,
a4h = 277, //A4大小,210mm x 297mm,四邊各保留10mm的邊距,顯示區(qū)域190x277
imgHeight = Math.floor(a4h * canvas.width / a4w), //按A4顯示比例換算一頁圖像的像素高度
renderedHeight = 0;
while (renderedHeight < canvas.height) {
let page = document.createElement("canvas");
page.width = canvas.width;
page.height = Math.min(imgHeight, canvas.height - renderedHeight); //可能內(nèi)容不足一頁
//用getImageData剪裁指定區(qū)域,并畫到前面創(chuàng)建的canvas對象中
page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(
imgHeight, canvas.height - renderedHeight)), 0, 0);
pdf.addImage(page.toDataURL('image/jpeg', 0.2), 'JPEG', 10, 10, a4w, Math.min(a4h, a4w * page.height /
page.width)); //添加圖像到頁面,保留10mm邊距
renderedHeight += imgHeight;
if (renderedHeight < canvas.height) pdf.addPage(); //如果后面還有內(nèi)容,添加一個空頁
}
pdf.save('測試.pdf');
}
})
demo.style.overflow = 'auto';
}
主要是對onrendered()方法進行了一點小優(yōu)化,四邊各保留10mm的邊距。這樣看起開和平時看到的PDF大致差不多。另外需要注意的地方就是如果頁面是有滾動的需要添加 demo.style.overflow = 'visible';不然滾動區(qū)域以外的部分是會被截斷導出不了的。
最后看下優(yōu)化后的內(nèi)容:

image.png