我一直在开发一个投票应用程序。用户能够创建自己的投票并获取有关所提问的数据。我想添加功能,使用户可以将结果以PDF格式下载。
例如,我有两个组件负责获取问题和数据。
<QuestionBox />
<ViewCharts />
我想把这两个组件输出到一个PDF文件中,用户可以下载这个PDF文件。我找到了几个可以在组件内部呈现PDF的软件包。但是,我没有找到可以从虚拟DOM组成的输入流生成PDF的软件包。如果我想从头开始实现这个功能,应该采用什么方法?
我一直在开发一个投票应用程序。用户能够创建自己的投票并获取有关所提问的数据。我想添加功能,使用户可以将结果以PDF格式下载。
例如,我有两个组件负责获取问题和数据。
<QuestionBox />
<ViewCharts />
我想把这两个组件输出到一个PDF文件中,用户可以下载这个PDF文件。我找到了几个可以在组件内部呈现PDF的软件包。但是,我没有找到可以从虚拟DOM组成的输入流生成PDF的软件包。如果我想从头开始实现这个功能,应该采用什么方法?
将React渲染成PDF通常很麻烦,但可以使用canvas解决。
思路是将: HTML -> Canvas -> PNG(或JPEG) -> PDF
为了实现上述目标,您需要:
import React, {Component, PropTypes} from 'react';
// download html2canvas and jsPDF and save the files in app/ext, or somewhere else
// the built versions are directly consumable
// import {html2canvas, jsPDF} from 'app/ext';
export default class Export extends Component {
constructor(props) {
super(props);
}
printDocument() {
const input = document.getElementById('divToPrint');
html2canvas(input)
.then((canvas) => {
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF();
pdf.addImage(imgData, 'JPEG', 0, 0);
// pdf.output('dataurlnewwindow');
pdf.save("download.pdf");
})
;
}
render() {
return (<div>
<div className="mb5">
<button onClick={this.printDocument}>Print</button>
</div>
<div id="divToPrint" className="mt4" {...css({
backgroundColor: '#f5f5f5',
width: '210mm',
minHeight: '297mm',
marginLeft: 'auto',
marginRight: 'auto'
})}>
<div>Note: Here the dimensions of div are same as A4</div>
<div>You Can add any component here</div>
</div>
</div>);
}
}
由于未导入所需文件,此代码片段在此处将无法运行。
另一种方法在此答案中被使用,其中省略了中间步骤,您可以直接从HTML转换为PDF。在jsPDF文档中也有这样的选项,但是从个人观察来看,当dom先转换为png时可以获得更好的准确性。
更新0:2018年9月14日
使用此方法创建的pdf上的文本将不可选择。如果这是要求,您可能会发现这篇文章会很有帮助。
只需几个步骤,我们就可以从我们的HTML页面下载或生成PDF,或者我们可以从HTML页面生成特定div的PDF。
步骤:HTML -> 图像(PNG或JPEG) -> PDF
请按照以下步骤操作:
第1步:
npm install --save html-to-image
npm install jspdf --save
第二步:
/* ES6 */
import * as htmlToImage from 'html-to-image';
import { toPng, toJpeg, toBlob, toPixelData, toSvg } from 'html-to-image';
/* ES5 */
var htmlToImage = require('html-to-image');
-------------------------
import { jsPDF } from "jspdf";
步骤三:
****** With out PDF properties given below ******
htmlToImage.toPng(document.getElementById('myPage'), { quality: 0.95 })
.then(function (dataUrl) {
var link = document.createElement('a');
link.download = 'my-image-name.jpeg';
const pdf = new jsPDF();
pdf.addImage(dataUrl, 'PNG', 0, 0);
pdf.save("download.pdf");
});
****** With PDF properties given below ******
htmlToImage.toPng(document.getElementById('myPage'), { quality: 0.95 })
.then(function (dataUrl) {
var link = document.createElement('a');
link.download = 'my-image-name.jpeg';
const pdf = new jsPDF();
const imgProps= pdf.getImageProperties(dataUrl);
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
pdf.addImage(dataUrl, 'PNG', 0, 0,pdfWidth, pdfHeight);
pdf.save("download.pdf");
});
我认为这很有帮助。请尝试。
你可以使用jsPDF结合画布(canvas)
import jsPDF from 'jspdf';
import html2canvas from 'html2canvas';
_exportPdf = () => {
html2canvas(document.querySelector("#capture")).then(canvas => {
document.body.appendChild(canvas); // if you want see your screenshot in body.
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF();
pdf.addImage(imgData, 'PNG', 0, 0);
pdf.save("download.pdf");
});
}
你的id为capture的div是:
<div id="capture">
<p>Hello in my life</p>
<span>How can hellp you</span>
</div>
const pdf = new jsPDF('p', 'pt', 'a4', false);
,第二行是将图像粘贴到pdf行pdf.addImage(imgData, 'PNG', 0, 0, 600, 0, undefined, false);
。如果您想调整pdf中捕获图像的宽度或高度,则可以玩弄addImage函数的第5个参数。疯狂一下吧 :P - imran haiderhtml2canvas
和 jspdf
库之外,我发现还有一个简单易用的库叫做 react-to-print
,可以将 React 组件下载为 PDF 文件,这里是该库的链接:https://www.npmjs.com/package/react-to-print。
它的文档、示例和演示都非常棒。
它甚至为基于类和基于函数的组件用户提供了文档。import React, { useRef } from 'react';
import { useReactToPrint } from 'react-to-print';
import { ComponentToPrint } from './ComponentToPrint';
const Example = () => {
const componentRef = useRef();
const handlePrint = useReactToPrint({
content: () => componentRef.current,
});
return (
<div>
<ComponentToPrint ref={componentRef} />
<button onClick={handlePrint}>Print this out!</button>
</div>
);
};
my opinion :
import { useRef } from "react";
import { jsPDF } from "jspdf";
import html2canvas from "html2canvas";
import "./styles.css";
const App = () => {
const inputRef = useRef(null);
const printDocument = () => {
html2canvas(inputRef.current).then((canvas) => {
const imgData = canvas.toDataURL("image/png");
const pdf = new jsPDF();
pdf.addImage(imgData, "JPEG", 0, 0);
pdf.save("download.pdf");
});
};
return (
<>
<div className="App">
<div className="mb5">
<button onClick={printDocument}>Print</button>
</div>
<div id="divToPrint" ref={inputRef}>
<div>Note: Here the dimensions of div are same as A4</div>
<div>You Can add any component here</div>
</div>
</div>
</>
);
};
export default App;
link demo:
https://codesandbox.io/s/frosty-sea-44b4q?file=/src/App.js:0-907
import React from "react";
import ReactDOMServer from "react-dom/server";
import jsPDF from 'jspdf';
然后:
var doc = new jsPDF();
doc.fromHTML(ReactDOMServer.renderToStaticMarkup(this.render()));
doc.save("myDocument.pdf");
建议使用:
renderToStaticMarkup
而不是:
renderToString
因为前者包含react所依赖的HTML代码。
// Get List of paged elements.
let elems = document.querySelectorAll('.elemClass');
let pdf = new jsPDF("portrait", "mm", "a4");
// Fix Graphics Output by scaling PDF and html2canvas output to 2
pdf.scaleFactor = 2;
// Create a new promise with the loop body
let addPages = new Promise((resolve,reject)=>{
elems.forEach((elem, idx) => {
// Scaling fix set scale to 2
html2canvas(elem, {scale: "2"})
.then(canvas =>{
if(idx < elems.length - 1){
pdf.addImage(canvas.toDataURL("image/png"), 0, 0, 210, 297);
pdf.addPage();
} else {
pdf.addImage(canvas.toDataURL("image/png"), 0, 0, 210, 297);
console.log("Reached last page, completing");
}
})
setTimeout(resolve, 100, "Timeout adding page #" + idx);
})
addPages.finally(()=>{
console.log("Saving PDF");
pdf.save();
});
npm install jspdf --save
//React中的代码
import jsPDF from 'jspdf';
var doc = new jsPDF()
doc.fromHTML("<div>JOmin</div>", 1, 1)
onclick //
doc.save("name.pdf")
<style>
标签,因此您必须编写内联CSS。 - Matias Faure