使用html2canvas和jspdf在React中从HTML生成pdf [英] generating pdf from Html in React using html2canvas and jspdf

查看:356
本文介绍了使用html2canvas和jspdf在React中从HTML生成pdf的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在React中成功地从html2canvas和jspdf生成了pdf.但是问题是pdf中渲染的图像被拉伸了.请让我知道进行此类工作的最佳选择是什么.是否有可能不使用html2canvas将HTML直接呈现为pdf? 以下是我的截图 输出屏幕截图 pdf的屏幕截图

I have successfully generated the pdf from html2canvas and jspdf in React. But the problem is the image rendered in the pdf is stretched. Please let me know what the best option to do this kind of work is. Is there any possibility of rendering the HTML directly to pdf without using html2canvas? Below are my screenshots Output Screenshot and pdf's screenshot

下面是我的代码

import React, { Component } from 'react';
import * as jsPDF from 'jspdf';
import * as html2canvas from 'html2canvas';


class Invoice extends Component {

handlePdf = () => {
    const input = document.getElementById('page');

    html2canvas(input)
        .then((canvas) => {
            const imgData = canvas.toDataURL('image/png');
            const pdf = new jsPDF('p', 'px', 'a4');
            var width = pdf.internal.pageSize.getWidth();
            var height = pdf.internal.pageSize.getHeight();

            pdf.addImage(imgData, 'JPEG', 0, 0, width, height);
            pdf.save("test.pdf");
        });
};

render() {

    const hrStyle = {
        border: '5px solid rgb(23, 162, 184)'
    };

    const subtotal = [0, ...this.props.inputs.totals];
    const add = (a, b) => a + b;
    const sum = subtotal.reduce(add);

    const tax = sum * 0.1;
    const total = sum + tax;

    return (
        <React.Fragment>
            <div className="col-12 col-lg-6" id="page">
                <div className="container-fluid bg-info text-white">
                    <div className="row">
                        <div className="col text-left m-2">
                            <p>Your Company Name</p>
                            <h2>Invoice</h2>
                        </div>
                        <div className="col text-right">
                            <p>22 Yusen St</p><br />
                            <p>borburn</p><br />
                            <p>WSN</p>
                        </div>
                    </div>
                </div>
                <div className="container-fluid">
                    <div className="row">
                        <div className="col-4">
                            <h5>Billed To</h5>
                            <p>{this.props.inputs.company}</p>
                            <p>{this.props.inputs.address}</p>
                            <p>{this.props.inputs.zip}</p>
                        </div>
                        <div className="col-4">
                            <div>
                                <h5>Invoive number</h5>
                                <p>Za{Math.floor((Math.random() * 100) + 1)}</p>
                            </div>
                            <div>
                                <h5>Date</h5>
                                <p>{this.props.inputs.date}</p>
                            </div>
                        </div>
                        <div className="col-4">
                            <div>
                                <h5>Invoice Totals</h5>
                                <p>${total}</p>
                            </div>
                        </div>
                    </div>
                </div>
                <hr style={hrStyle} />
                <div className="Invoices">
                    <table className="table">
                        <thead>
                            <tr>
                                <th>Description</th>
                                <th>Unit Price</th>
                                <th>Quantity</th>
                                <th>Total</th>
                            </tr>
                        </thead>
                        <tbody>
                            {this.props.inputs.invoices.map((invoice, index) => {
                                return (
                                    <tr key={index}>
                                        <td>{invoice.description}</td>
                                        <td>{invoice.unit}</td>
                                        <td>{invoice.quantity}</td>
                                        <td>{invoice.quantity * invoice.unit}</td>
                                    </tr>
                                )
                            })
                            }
                        </tbody>
                    </table>
                </div>
                <hr />
                <div className="col-12 text-right" >
                    <h5 className="m-2">
                        Subtotal<span className="m-2">${sum}</span>
                    </h5 >
                    <p>Tax(10%)<span className="m-2">${tax.toFixed(2)}</span></p>
                    <h2>Total<span className="m-2">${total}</span></h2>
                </div>
            </div>
            <button onClick={this.handlePdf} className="btn btn-primary btn-lg mx-auto">Generate PDF</button>

        </React.Fragment >
    );
}
}

export default Invoice;

推荐答案

您可以使用出色的 React-pdf 库.它具有良好的性能,并具有额外的好处,即,如果您打印文本,则可以进行搜索.

You can use the excellent React-pdf library. It has good performance and has the added benefit that if you print text, it will be searchable.

如果您需要用DOM以及PDF格式呈现页面,我建议您自己创建 并使用它们代替dom标签(div,p等).通过使用这些原语,您将能够在dom和pdf中渲染相同的组件.

If you need to render the page in the DOM as well as in PDF, I recommend to create yourself primitives and use these instead of the dom tags (div, p, etc). By using these primitives, you will be able to render the same components in the dom as well as in a pdf.

以下是View原语的示例:

Here is an example of a View primitive:

import React from 'react';
import { View as ViewPDF } from '@react-pdf/renderer';
import { RENDERING_CONTEXT, withRenderingContext } from '../RenderingContext';

class View extends React.Component {
  render() {
    const { renderingContext, children, className, style } = this.props;
    const isPdf = renderingContext === RENDERING_CONTEXT.PDF;
    return isPdf
      ? <ViewPDF className={className} style={style}>
          {children}
        </ViewPDF>
      : <div className={className} style {style}>
          {children}
        </div>;
  }
}
export default withRenderingContext(View);

RenderingContext是一个上下文,您可以在其中存储当前的渲染上下文.然后,您只需要用设置正确上下文的提供程序包装pdf页面即可.正确的组件(来自react-pdf或dom)将根据渲染上下文使用.

The RenderingContext is a context in which you can store the current rendering context. Then, you only need to wrap your pdf page with a provider that sets the proper context. The right component (from react-pdf or dom) will be used based on the rendering context.

在您的示例中,您可以简单地用这些原语替换Invoice中的dom元素.然后,您将可以在pdf文件或dom中渲染Invoice组件.

In your example, you could simply replace the dom element in Invoice with these primitives. Then, you would be able to render the Invoice component in a pdf file or in the dom.

这篇关于使用html2canvas和jspdf在React中从HTML生成pdf的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆