从React组件生成PDF文件

Oza*_*zan 28 pdf meteor reactjs

我一直在构建一个轮询应用程序.人们可以创建他们的民意调查并获得有关他们提出的问题的数据.我想添加功能,让用户以PDF的形式下载结果.

例如,我有两个组件负责抓取问题和数据.

<QuestionBox />
<ViewCharts />
Run Code Online (Sandbox Code Playgroud)

我正在尝试将两个组件输出到PDF文件中.然后,用户可以下载此PFD文件.我找到了一些允许在组件内部呈现PDF的包.但是,我找不到可以从包含虚拟DOM的输入流生成PDF的方法.如果我想从头开始实现这一目标,我应该遵循哪种方法?

Shi*_*ana 66

渲染反应因为pdf通常很痛苦,但是有一种方法可以使用canvas.

想法是转换:HTML - >画布 - > PNG(或JPEG) - > PDF

要实现上述目标,您需要:

  1. html2canvas&
  2. jsPDF

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>);
  }
}
Run Code Online (Sandbox Code Playgroud)

该片段在此处不起作用,因为未导入所需的文件.

这个答案中使用了另一种方法,其中中间步骤被删除,您可以简单地从HTML转换为PDF.在jsPDF文档中也可以选择这样做,但是从个人观察来看,我觉得当dom首先转换为png时可以获得更好的准确性.

更新0:2018年9月14日

此方法创建的pdf上的文本将无法选择.如果这是一项要求,您可能会发现本文很有帮助.

  • 在您的回答的帮助下,我已成功从 html 页面创建了 PDF 文件。但是如果我们想创建一个多页的PDF,该怎么办呢?a4 尺寸的页面各边都有适当的边距,并且在每个新页面中都应应用该边距。请帮我它的银色。先感谢您。我在这里创建了一个问题[问题](/sf/ask/3327055581/) (2认同)
  • @ShivekKhurana 我的 div 根据屏幕大小而变化,但我希望 PDF 文件始终相同,而不取决于窗口大小。我能做到吗?另外,我如何导入 {...css} ? (2认同)
  • 通过这种方法可以复制创建的pdf上的文本吗? (2认同)

小智 15

React-PDF是一个很好的资源。

将标记和 CSS 转换为 React-PDF 的格式有点耗时,但很容易理解。导出 PDF 并从中导出相当简单。

要允许用户下载由react-PDF生成的PDF,请使用它们的动态渲染,它提供了可自定义的下载链接。单击后,站点将为用户呈现并下载 PDF。

这是他们的REPL,它将使您熟悉所需的标记和样式。他们也有 PDF 的下载链接,但这里没有显示该链接的代码。


Moh*_* MK 12

只需几步。我们可以从 HTML 页面下载或生成 PDF,也可以从 HTML 页面生成特定 div 的 PDF。

步骤:HTML -> 图像(PNG 或 JPEG) -> PDF

请按照以下步骤操作,

步骤1 :-

npm install --save html-to-image
npm install jspdf --save
Run Code Online (Sandbox Code Playgroud)

第2步 :-

/* 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";
Run Code Online (Sandbox Code Playgroud)

步骤 3 :-

   ******  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"); 
        });
Run Code Online (Sandbox Code Playgroud)

我认为这很有帮助。请尝试


Ara*_*ras 7

您可以使用 jsPDF 来使用画布

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"); 
    });

 }
Run Code Online (Sandbox Code Playgroud)

你用 id 捕获的 div 是:

例子

<div id="capture">
  <p>Hello in my life</p>
  <span>How can hellp you</span>
</div>
Run Code Online (Sandbox Code Playgroud)

  • 您为什么添加答案的副本? (5认同)

Ngu*_*hựt 7

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
Run Code Online (Sandbox Code Playgroud)


Jab*_*ian 6

除了使用html2canvasjspdf库之外,我还发现了另一个易于使用的库,需要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>
  );
};
Run Code Online (Sandbox Code Playgroud)


小智 5

您可以使用 ReactDOMServer 将组件渲染为 HTML,然后在 jsPDF 上使用它。

首先进行导入:

import React from "react";
import ReactDOMServer from "react-dom/server";
import jsPDF from 'jspdf';
Run Code Online (Sandbox Code Playgroud)

然后:

var doc = new jsPDF();
doc.fromHTML(ReactDOMServer.renderToStaticMarkup(this.render()));
doc.save("myDocument.pdf");
Run Code Online (Sandbox Code Playgroud)

更喜欢使用:

渲染到静态标记

代替:

渲染到字符串

由于前者包含了react依赖的HTML代码。

  • 看起来很有趣,但是 renderToStaticMarkup 不会返回任何样式,所以据我所知,jsPDF 只是渲染原始 html 的一些默认布局,除非有某种方法可以注入 css 类? (2认同)