使用Javascript从div中的HTML生成pdf

我有以下html代码:

<!DOCTYPE html>
<html>
<body>
<p>don't print this to pdf</p>
<div id="pdf">
<p><font size="3" color="red">print this to pdf</font></p>
</div>
</body>
</html>

所有我想做的是打印到pdf,无论在div中找到一个id为“pdf”。这必须使用JavaScript来完成。"pdf"文件会自动下载,文件名为"foobar.pdf"

我一直在使用jspdf来做到这一点,但它唯一的功能是“文本”,只接受字符串值。我想提交HTML到jspdf,而不是文本。

1279038 次浏览

你可以使用autoPrint()并将输出设置为'dataurlnewwindow',如下所示:

function printPDF() {
var printDoc = new jsPDF();
printDoc.fromHTML($('#pdf').get(0), 10, 10, {'width': 180});
printDoc.autoPrint();
printDoc.output("dataurlnewwindow"); // this opens a new popup,  after this the PDF opens the print window view but there are browser inconsistencies with how this is handled
}

jsPDF能够使用插件。为了使它能够打印HTML,你必须包括某些插件,因此必须做以下事情:

  1. 进入https://github.com/MrRio/jsPDF并下载最新版本。
  2. 在你的项目中包含以下脚本:
    • jspdf.js
    • jspdf.plugin.from_html.js
    • jspdf.plugin.split_text_to_size.js
    • jspdf.plugin.standard_fonts_metrics.js
    • 李< / ul > < / >

如果希望忽略某些元素,则必须用ID标记它们,然后可以在jsPDF的特殊元素处理程序中忽略该ID。因此你的HTML应该是这样的:

<!DOCTYPE html>
<html>
<body>
<p id="ignorePDF">don't print this to pdf</p>
<div>
<p><font size="3" color="red">print this to pdf</font></p>
</div>
</body>
</html>

然后使用以下JavaScript代码在弹出窗口中打开创建的PDF:

var doc = new jsPDF();
var elementHandler = {
'#ignorePDF': function (element, renderer) {
return true;
}
};
var source = window.document.getElementsByTagName("body")[0];
doc.fromHTML(
source,
15,
15,
{
'width': 180,'elementHandlers': elementHandler
});


doc.output("dataurlnewwindow");

对我来说,这创建了一个漂亮而整洁的PDF,只包括一行“打印此PDF”。

请注意,特殊元素处理程序只处理当前版本中的id,这也是在GitHub的问题中声明的。州:

因为匹配是针对节点树中的每个元素进行的,所以我希望尽可能快地进行匹配。在这种情况下,它意味着“只匹配元素id”。元素id仍然是jQuery风格的“#id”,但这并不意味着支持所有的jQuery选择器。

因此,将'#ignorePDF'替换为'类选择器'。ignorePDF'没有为我工作。相反,你必须为每个元素添加相同的处理程序,你想忽略这些元素,比如:

var elementHandler = {
'#ignoreElement': function (element, renderer) {
return true;
},
'#anotherIdToBeIgnored': function (element, renderer) {
return true;
}
};

例子中还指出,可以选择像'a'或'li'这样的标记。不过,对于大多数用例来说,这可能有点不受限制:

我们支持特殊的元素处理程序。用jquery方式注册它们 ID选择器用于ID或节点名称。(“#iAmID”,“div”,“span”等) 不支持任何其他类型的选择器(class, of

要添加的一个非常重要的事情是,您丢失了所有的样式信息(CSS)。幸运的是,jsPDF能够很好地格式化h1、h2、h3等,这对我的目的来说已经足够了。此外,它只打印文本节点中的文本,这意味着它不会打印文本区域等的值。例子:

<body>
<ul>
<!-- This is printed as the element contains a textnode -->
<li>Print me!</li>
</ul>
<div>
<!-- This is not printed because jsPDF doesn't deal with the value attribute -->
<input type="textarea" value="Please print me, too!">
</div>
</body>

我能够得到jsPDF打印动态创建的表从一个div。

$(document).ready(function() {


$("#pdfDiv").click(function() {


var pdf = new jsPDF('p','pt','letter');
var specialElementHandlers = {
'#rentalListCan': function (element, renderer) {
return true;
}
};


pdf.addHTML($('#rentalListCan').first(), function() {
pdf.save("caravan.pdf");
});
});
});

工作伟大的Chrome和Firefox…格式在IE中都被放大了。

我还列出了以下内容:

<script src="js/jspdf.js"></script>
<script src="js/jspdf.plugin.from_html.js"></script>
<script src="js/jspdf.plugin.addhtml.js"></script>
<script src="//mrrio.github.io/jsPDF/dist/jspdf.debug.js"></script>
<script src="http://html2canvas.hertzen.com/build/html2canvas.js"></script>
<script type="text/javascript" src="./libs/FileSaver.js/FileSaver.js"></script>
<script type="text/javascript" src="./libs/Blob.js/Blob.js"></script>
<script type="text/javascript" src="./libs/deflate.js"></script>
<script type="text/javascript" src="./libs/adler32cs.js/adler32cs.js"></script>


<script type="text/javascript" src="js/jspdf.plugin.addimage.js"></script>
<script type="text/javascript" src="js/jspdf.plugin.sillysvgrenderer.js"></script>
<script type="text/javascript" src="js/jspdf.plugin.split_text_to_size.js"></script>
<script type="text/javascript" src="js/jspdf.plugin.standard_fonts_metrics.js"></script>

这是一个简单的解决方案。这对我很有用。你可以使用javascript打印概念,并简单地将其保存为pdf。

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript">
$("#btnPrint").live("click", function () {
var divContents = $("#dvContainer").html();
var printWindow = window.open('', '', 'height=400,width=800');
printWindow.document.write('<html><head><title>DIV Contents</title>');
printWindow.document.write('</head><body >');
printWindow.document.write(divContents);
printWindow.document.write('</body></html>');
printWindow.document.close();
printWindow.print();
});
</script>
</head>
<body>
<form id="form1">
<div id="dvContainer">
This content needs to be printed.
</div>
<input type="button" value="Print Div Contents" id="btnPrint" />
</form>
</body>
</html>

如果你想导出一个表,你可以看看Shield UI Grid小部件提供的此导出样例

它是通过像这样扩展配置来实现的:

...
exportOptions: {
proxy: "/filesaver/save",
pdf: {
fileName: "shieldui-export",
author: "John Smith",
dataSource: {
data: gridData
},
readDataSource: true,
header: {
cells: [
{ field: "id", title: "ID", width: 50 },
{ field: "name", title: "Person Name", width: 100 },
{ field: "company", title: "Company Name", width: 100 },
{ field: "email", title: "Email Address" }
]
}
}
}
...

如前所述,你应该使用jsPDFhtml2canvas。我还在jsPDF问题中发现了一个函数,它自动将您的pdf分成多个页面(来源)

function makePDF() {


var quotes = document.getElementById('container-fluid');


html2canvas(quotes, {
onrendered: function(canvas) {


//! MAKE YOUR PDF
var pdf = new jsPDF('p', 'pt', 'letter');


for (var i = 0; i <= quotes.clientHeight/980; i++) {
//! This is all just html2canvas stuff
var srcImg  = canvas;
var sX      = 0;
var sY      = 980*i; // start 980 pixels down for every new page
var sWidth  = 900;
var sHeight = 980;
var dX      = 0;
var dY      = 0;
var dWidth  = 900;
var dHeight = 980;


window.onePageCanvas = document.createElement("canvas");
onePageCanvas.setAttribute('width', 900);
onePageCanvas.setAttribute('height', 980);
var ctx = onePageCanvas.getContext('2d');
// details on this usage of this function:
// https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Using_images#Slicing
ctx.drawImage(srcImg,sX,sY,sWidth,sHeight,dX,dY,dWidth,dHeight);


// document.body.appendChild(canvas);
var canvasDataURL = onePageCanvas.toDataURL("image/png", 1.0);


var width         = onePageCanvas.width;
var height        = onePageCanvas.clientHeight;


//! If we're on anything other than the first page,
// add another page
if (i > 0) {
pdf.addPage(612, 791); //8.5" x 11" in pts (in*72)
}
//! now we declare that we're working on that page
pdf.setPage(i+1);
//! now we add content to that page!
pdf.addImage(canvasDataURL, 'PNG', 20, 40, (width*.62), (height*.62));


}
//! after the for loop is finished running, we save the pdf.
pdf.save('test.pdf');
}
});
}

要将div捕获为PDF,可以使用https://grabz.it解决方案。它有一个简单而灵活的JavaScript API,允许您捕获单个HTML元素(如div或span)的内容

为了实现它,你需要首先获得一个应用程序密钥和秘密下载(免费)SDK。

现在来看一个例子。

假设你有HTML:

<div id="features">
<h4>Acme Camera</h4>
<label>Price</label>$399<br />
<label>Rating</label>4.5 out of 5
</div>
<p>Cras ut velit sed purus porttitor aliquam. Nulla tristique magna ac libero tempor, ac vestibulum felisvulput ate. Nam ut velit eget
risus porttitor tristique at ac diam. Sed nisi risus, rutrum a metus suscipit, euismod tristique nulla. Etiam venenatis rutrum risus at
blandit. In hac habitasse platea dictumst. Suspendisse potenti. Phasellus eget vehicula felis.</p>

要捕获特征id下的内容,您需要:

//add the sdk
<script type="text/javascript" src="grabzit.min.js"></script>
<script type="text/javascript">
//login with your key and secret.
GrabzIt("KEY", "SECRET").ConvertURL("http://www.example.com/my-page.html",
{"target": "#features", "format": "pdf"}).Create();
</script>

请注意target: #feature#feature是你的CSS选择器,就像前面的例子一样。现在,当页面加载时,将在脚本标记的相同位置创建图像截图,其中将包含所有的功能div的内容,没有其他内容。

你可以对div-截图机制进行其他配置和自定义,请查看在这里

如果你需要下载一个特定页面的PDF文件,只需添加这样的按钮

<h4 onclick="window.print();"> Print </h4>

使用window.print()打印整个页面,而不仅仅是一个div

  • 没有依赖,纯JS
  • 要添加CSS或图像-不要使用相对url,使用完整url http://...domain.../path.css左右。它创建单独的HTML文档,没有主要内容的上下文。
  • 您还可以将图像嵌入为base64

多年来,这句话一直为我服务:

export default function printDiv({divId, title}) {
let mywindow = window.open('', 'PRINT', 'height=650,width=900,top=100,left=150');


mywindow.document.write(`<html><head><title>${title}</title>`);
mywindow.document.write('</head><body >');
mywindow.document.write(document.getElementById(divId).innerHTML);
mywindow.document.write('</body></html>');


mywindow.document.close(); // necessary for IE >= 10
mywindow.focus(); // necessary for IE >= 10*/


mywindow.print();
mywindow.close();


return true;
}

当然,这将打开打印对话框,用户必须知道她/他可以选择打印到pdf选项,以获得pdf。可能会有预先选定的打印机,如果用户确认,可以实际打印此文件。为了避免这种情况,并提供没有任何额外的PDF,您需要制作PDF文件。可能是在服务器端。你可以有微小的html页面与发票,并将其转换为PDF文件与无头铬。对木偶师来说超级简单。不需要安装/config chrome,只需安装npm包木偶(由chrome团队管理)并运行它。请记住,这实际上会启动真正的chrome只是w/o GUI,所以你需要一些RAM和amp;CPU。大多数服务器在流量足够低的情况下都没问题。这里是代码示例,但这必须在后台运行。Nodejs。而且这是缓慢的呼叫,是资源密集型的呼叫。你应该运行它不是在api调用,但例如,发票创建后-创建pdf为它和存储,如果pdf还没有生成,只是显示消息再试几分钟。

const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://your-domain.com/path-to-invoice', {
waitUntil: 'networkidle2',
});
await page.pdf({ path: 'invoice-file-path.pdf', format: 'a4' });


await browser.close();
})();

在这里了解更多:https://pptr.dev/

我使用jspdfhtml2canvas进行css渲染,我导出特定div的内容,因为这是我的代码

$(document).ready(function () {
let btn=$('#c-oreder-preview');
btn.text('download');
btn.on('click',()=> {


$('#c-invoice').modal('show');
setTimeout(function () {
html2canvas(document.querySelector("#c-print")).then(canvas => {
//$("#previewBeforeDownload").html(canvas);
var imgData = canvas.toDataURL("image/jpeg",1);
var pdf = new jsPDF("p", "mm", "a4");
var pageWidth = pdf.internal.pageSize.getWidth();
var pageHeight = pdf.internal.pageSize.getHeight();
var imageWidth = canvas.width;
var imageHeight = canvas.height;


var ratio = imageWidth/imageHeight >= pageWidth/pageHeight ? pageWidth/imageWidth : pageHeight/imageHeight;
//pdf = new jsPDF(this.state.orientation, undefined, format);
pdf.addImage(imgData, 'JPEG', 0, 0, imageWidth * ratio, imageHeight * ratio);
pdf.save("invoice.pdf");
//$("#previewBeforeDownload").hide();
$('#c-invoice').modal('hide');
});
},500);


});
});

一种方法是使用window.print()函数。哪个不需要任何库

优点

1.不需要外部库。

2.我们也可以只打印选定的身体部位。

3.没有css冲突和js问题。

4.html/js核心功能

简单地添加下面的代码

CSS

@media print {
body * {
visibility: hidden; // part to hide at the time of print
-webkit-print-color-adjust: exact !important; // not necessary use
if colors not visible
}


#printBtn {
visibility: hidden !important; // To hide
}


#page-wrapper * {
visibility: visible; // Print only required part
text-align: left;
-webkit-print-color-adjust: exact !important;
}
}

JS代码-调用btn点击下面的功能

$scope.printWindow = function () {
window.print()
}

注意:在每个css对象中使用!important

的例子,

.legend  {
background: #9DD2E2 !important;
}

使用pdfMake.js这个要点

(我找到了Gist 在这里html-to-pdfmake包的链接,我现在没有使用它。)

npm install pdfmake之后,将Gist保存在htmlToPdf.js中,我这样使用它:

const pdfMakeX = require('pdfmake/build/pdfmake.js');
const pdfFontsX = require('pdfmake-unicode/dist/pdfmake-unicode.js');
pdfMakeX.vfs = pdfFontsX.pdfMake.vfs;
import * as pdfMake from 'pdfmake/build/pdfmake';
import htmlToPdf from './htmlToPdf.js';


var docDef = htmlToPdf(`<b>Sample</b>`);
pdfMake.createPdf({content:docDef}).download('sample.pdf');

备注:

  • 我的用例是从markdown文档(使用markdown-it)创建相关的html,随后生成pdf,并上传其二进制内容(我可以使用pdfMakegetBuffer()函数),所有这些都来自浏览器。生成的pdf被证明是更好的这种html比与其他解决方案,我已经尝试。
  • 我对我从接受的答案中建议的jsPDF.fromHTML()得到的结果不满意,因为该解决方案很容易被我的HTML中的特殊字符所混淆,这些字符显然被解释为一种标记,完全混乱了产生的PDF。
  • 使用基于画布的解决方案(如已弃用的jsPDF.from_html()函数,不要与接受的答案相混淆)对我来说不是一个选项,因为我希望生成的PDF中的文本是可粘贴的,而基于画布的解决方案生成基于位图的PDF。
  • 直接降价到pdf转换器,如md-to-pdf是服务器端,不会为我工作。
  • 使用浏览器的打印功能不适合我,因为我不想显示生成的PDF,而是上传其二进制内容。

这个例子效果很好。

<button onclick="genPDF()">Generate PDF</button>


<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.min.js"></script>
<script>
function genPDF() {
var doc = new jsPDF();
doc.text(20, 20, 'Hello world!');
doc.text(20, 30, 'This is client-side Javascript, pumping out a PDF.');
doc.addPage();
doc.text(20, 20, 'Do you like that?');
    

doc.save('Test.pdf');
}
</script>

有人试过吗

    (function () {
var
form = $('.form'),
cache_width = form.width(),
a4 = [595.28, 841.89]; // for a4 size paper width and height


$('#create_pdf').on('click', function () {
$('body').scrollTop(0);
createPDF();
});
//create pdf
function createPDF() {
getCanvas().then(function (canvas) {
var
img = canvas.toDataURL("image/png"),
doc = new jsPDF({
unit: 'px',
format: 'a4'
});
doc.addImage(img, 'JPEG', 20, 20);
doc.save('Bhavdip-html-to-pdf.pdf');
form.width(cache_width);
});
}


// create canvas object
function getCanvas() {
form.width((a4[0] * 1.33333) - 80).css('max-width', 'none');
return html2canvas(form, {
imageTimeout: 2000,
removeContainer: true
});
}


}());

不满意html2canvas的渲染和缺乏现代CSS3/JS和打印特定的CSS支持pdfMake的过时版本的WebKit…

这是一个理论上的解决方案,它是无头的,可以忠实地渲染页面,支持分页符,页边距,不同的页面大小,并且可以自动化。你甚至可以把WebGl渲染成PDF。

在chrome_devtools协议上执行printToPDF命令:

printToPDF({
printBackground: false,
pageWidth: 8.5,
pageHeight: 11,
transferMode: "ReturnAsStream" // or ReturnAsBase64
})


2022答:

从HTML元素生成PDF并提示保存文件:

import { jsPDF } from "jsPDF"


function generatePDF() {
const doc = new jsPDF({ unit: 'pt' }) // create jsPDF object
const pdfElement = document.getElementById('pdf') // HTML element to be converted to PDF


doc.html(pdfElement, {
callback: (pdf) => {
pdf.save('MyPdfFile.pdf')
},
margin: 32, // optional: page margin
// optional: other HTMLOptions
})
}
<button onclick="generatePDF()">Save PDF</button>

...

不打印预览PDF文件:

doc.html(pdfElement, {
callback: (pdf) => {
const myPdfData = pdf.output('datauristring')
}
})
<embed type="application/pdf" src={myPdfData} />
< p >…
更多的HTMLOptions:
https://github.com/parallax/jsPDF/blob/master/types/index.d.ts < / p >

下面的方法对我的案例很有效。

隐藏页面的其他部分,如下例所示

@media print{
body{
-webkit-print-color-adjust: exact; // if you want to enable graphics
color-adjust: exact !important; // if you want to enable graphics
print-color-adjust: exact !important; // if you want to enable graphics
       

* {
visibility: hidden;
margin:0;
padding:0
}
.print_area, .print_area *{
visibility: visible;
}
.print_area{
margin: 0;
align: center;
}
.pageBreak {
page-break-before : always; // If you want to skip next page
page-break-inside: avoid;  // If you want to skip next page
}
}
@page {
size: A4; margin:0mm; // set page layout
background-color: #fff;
}
}

使用javascript的print函数来打印执行。

<button onclick="window.print()">Print</button>