it-swarm.com.de

A generieren PDF Datei von React Components

Ich habe eine Abrufanwendung erstellt. Die Leute können ihre Umfragen erstellen und erhalten Daten zu den Fragen, die sie stellen. Ich möchte die Funktionalität hinzufügen, damit die Benutzer die Ergebnisse in Form einer PDF-Datei herunterladen können.

Ich habe zum Beispiel zwei Komponenten, die für das Erfassen der Frage und der Daten verantwortlich sind.

<QuestionBox />
<ViewCharts />

Ich versuche, beide Komponenten in eine PDF -Datei auszugeben. Der Benutzer kann diese PFD-Datei herunterladen. Ich habe ein paar Pakete gefunden, die das Rendern eines PDF in einer Komponente ermöglichen. Ich habe jedoch keinen gefunden, der PDF aus einem Eingabestrom erzeugen kann, der aus einem virtuellen DOM besteht. Wenn ich das von Grund auf erreichen möchte, welcher Vorgehensweise sollte ich folgen? 

23
Ozan

Das Rendern als PDF ist im Allgemeinen ein Problem, aber es gibt einen Weg, es mithilfe von Canvas zu umgehen. 

Die Idee ist, Folgendes zu konvertieren: HTML -> Canvas -> PNG (oder JPEG) -> PDF

Um dies zu erreichen, benötigen Sie:

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

Das Snippet funktioniert hier nicht, da die erforderlichen Dateien nicht importiert werden.

In dieser Antwort wird ein alternativer Ansatz verwendet, bei dem die mittleren Schritte gelöscht werden und Sie einfach von HTML in PDF konvertieren können. Es gibt auch eine Option, dies in der jsPDF-Dokumentation zu tun, aber aus persönlicher Beobachtung glaube ich, dass eine bessere Genauigkeit erreicht wird, wenn dom zuerst in png umgewandelt wird.

Update 0: 14. September 2018

Der auf diesem Weg erstellte Text in den PDF-Dateien kann nicht ausgewählt werden. Wenn dies eine Voraussetzung ist, können Sie diesen Artikel hilfreich finden.

57
Shivek Khurana

sie können Benutzer-Canvans mit jsPDF erstellen

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

 }

und du div mit id capture ist:

beispiel

<div id="capture">
  <p>Hello in my life</p>
  <span>How can hellp you</span>
</div>
2
Aras
npm install jspdf --save

// Code auf reagieren 

import jsPDF from 'jspdf';


var doc = new jsPDF()


 doc.fromHTML("<div>JOmin</div>", 1, 1)


onclick //

 doc.save("name.pdf")
1

Sie können ReactPDF verwenden

Ermöglicht das einfache Konvertieren eines Divs in PDF. Sie müssen Ihr vorhandenes Markup anpassen, um ReactPDF-Markup verwenden zu können, aber es lohnt sich.

1
Sooraj Chandran

Dies ist möglicherweise keine suboptimale Vorgehensweise, aber die einfachste Lösung für das von mir gefundene mehrseitige Problem bestand darin, sicherzustellen, dass vor dem Aufruf der jsPDFObj.save-Methode alles gerendert wird.

Was das Rendern verborgener Artikel angeht, so wurde dieses Problem mit einem ähnlichen Fix für das Ersetzen von CSS-Bildtext behoben. Ich positioniere das zu rendernde Element absolut auf der linken Seite, Dies wirkt sich nicht auf das Layout aus und ermöglicht es dem Element sichtbar für html2pdf, insbesondere bei der Verwendung von Registerkarten, Akkordeons und anderen Komponenten der Benutzeroberfläche, die von {display: none} abhängen.

Diese Methode fasst die Voraussetzungen in einem Versprechen zusammen und ruft pdf.save() in der finally()-Methode auf. Ich kann nicht sicher sein, dass dies narrensicher ist, oder ein Anti-Pattern, aber es scheint, dass es in den meisten Fällen funktioniert, die ich darauf geworfen habe.

// 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();
});

1
Tech1337

Sie können ReactDOMServer verwenden, um Ihre Komponente in HTML zu rendern und diese dann für jsPDF zu verwenden.

Zuerst die Importe:

import React from "react";
import ReactDOMServer from "react-dom/server";

dann:

var doc = new jsPDF();
doc.fromHTML(ReactDOMServer.renderToStaticMarkup(this.render()));
doc.save("myDocument.pdf");

Lieber verwenden:

renderToStaticMarkup

anstatt:

renderToString

Als erster enthalten HTML-Code, auf den reagiert.

0
Rodrigo Alencar