Создание файла PDF из компонентов React

Я создаю приложение для опроса. Люди могут создавать свои опросы и получать данные по вопросам, которые они задают. Я хотел бы добавить функциональность, чтобы пользователи могли загружать результаты в виде PDF.

Например, у меня есть два компонента, которые отвечают за захват вопроса и данных.

<QuestionBox />
<ViewCharts />

Я пытаюсь вывести оба компонента в файл PDF. Затем пользователь может загрузить этот файл PFD. Я нашел несколько пакетов, которые разрешают рендеринг PDF внутри компонента. Однако мне не удалось найти файл, который может генерировать PDF из входного потока, состоящего из виртуального DOM. Если я хочу добиться этого с нуля, какой подход следует придерживаться?

Ответ 1

Реакция рендеринга как pdf - это, как правило, боль, но есть способ обойти это, используя canvas.

Идея состоит в том, чтобы конвертировать: HTML → Canvas → 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>);
  }
}

Ответ 2

Вы можете использовать canvans с 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"); 
    });

 }

и вы div с захватом идентификатора:

пример

<div id="capture">
  <p>Hello in my life</p>
  <span>How can hellp you</span>
</div>

Ответ 3

Это может или не может быть неоптимальным способом выполнения действий, но самое простое решение многостраничной проблемы, которую я обнаружил, состояло в том, чтобы убедиться, что весь рендеринг выполняется перед вызовом метода jsPDFObj.save.

Что касается рендеринга скрытых статей, это решается аналогично исправлению, аналогичному замене текста в изображении CSS, я размещаю абсолютно элемент, который будет отображаться -9999px, слева от страницы, это не влияет на макет и позволяет элементу быть видимым для html2pdf, особенно при использовании вкладок, аккордеонов и других компонентов пользовательского интерфейса, которые зависят от {display: none}.

Этот метод оборачивает предварительные условия в обещании и вызывает pdf.save() в методе finally(). Я не могу быть уверен, что это надежная защита или шаблон, но может показаться, что в большинстве случаев это срабатывает.

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

Ответ 4

npm install jspdf --save

//код на реакцию

import jsPDF from 'jspdf';


var doc = new jsPDF()


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


onclick //

 doc.save("name.pdf")

Ответ 5

Вы можете использовать ReactDOMServer для рендеринга вашего компонента в HTML, а затем использовать его в jsPDF.

Сначала сделайте импорт:

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

затем:

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

Предпочитаю использовать:

renderToStaticMarkup

вместо:

renderToString

В качестве первого включают HTML-код, который реагирует на.

Ответ 6

Я использовал для печати текущей страницы в формате pdf с использованием js pdf, также я создал демо-версию, для которой вы можете перейти или обратиться к этому [ https://github.com/AkashMishraMS/React-Pdf][1], вы можете получить больше ясности также для Многостраничное создание PDF вы можете рассчитать размер холста и SVG и распечатать. и скоро я создам демо для этого тоже.

[1]: https://github.com/AkashMishraMS/React-Pdf.

Ответ 7

Вы можете использовать ReactPDF

Позволяет легко конвертировать div в PDF.