【问题标题】:React Component To PDF将组件反应为 PDF
【发布时间】:2021-02-05 17:16:00
【问题描述】:

我正在开发一项功能,该功能将允许用户完成其管道的最后阶段并从中获取精美的 PDF。

我的服务器和客户端都玩得很好。我一直无法完成的是将整个文档放入 pdf 中。它只捕获一小部分。

我不需要多个页面,尽管那会很好。无论渲染多长时间,我只想捕获所有内容。有可能有 100 个项目,例如图像和旁边的复选框。我需要一个完整的 pdf,到目前为止我只能得到其中一小部分的快照。

我尝试弄乱高度选项和各种包,但绝对没有运气。

我将提供 renderSimpleForm 最终在浏览器上的样子。以及它作为 PDF 出现的内容。


代码和图片


import { jsPDF } from "jspdf";
import * as htmlToImage from 'html-to-image';

        const handleSubmit = () => {
            // //Before sending the action show in progress text and disable button
            setPdf({inProgress: true})

            //Creating the pdf blob
            htmlToImage.toPng(document.getElementById('simpleForm'))
            .then(function (dataUrl) {
              var link = document.createElement('a');
              link.download = 'my-image-name.jpeg';
              const pdf = new jsPDF('p', 'mm', 'a4');
              const imgProps= pdf.getImageProperties(dataUrl);
              pdf.addImage(dataUrl, 'PNG', 0, 0);
              //Send action to server
              ClassInstancesActions.StorePassportPDFToDisk(pdf.output('blob'), productID)
            });
        }

        return (
            <div id="simpleForm" style={{ height: '9999px !important', width: '9999px !important' }}>
                {renderSimpleForm()}
                {showError()}
                {renderSubmitCancel(disableSubmit)}
            </div>
        );
    };
这是我的 SUMIT 按钮的输出 这就是它在浏览器上的显示方式

【问题讨论】:

    标签: javascript reactjs pdf jspdf react-to-pdf


    【解决方案1】:

    好的,过了一段时间我有一个可以满足我需求的解决方案:

    1. 指向 React 组件中的 div,并将其 pdf 格式
    2. 保留样式

    还有额外的:

    1. 能够以编程方式自定义和控制我在数据库中的元数据
    2. 自定义是添加页眉、页脚、页码、首页,我可以从技术上控制每一页

    我用https://www.npmjs.com/package/@progress/kendo-react-pdf

    我使用了它的 savePDF 函数,该函数还允许我使用模板创建类型功能,因为它是免费的,并且作为你将在代码中看到的选项参数中的道具传入。

    还有一个 css 选择器,它只针对已传递的 PDF 的 div,无需指定要显示的内容和不显示的内容,因此您可以在 PDF 完全从这里完全出来之前对其进行操作。

    在视频演示中,您会看到我有一个超过 40 页的 MASSIVE div! 保留了我的材质和 CSS 样式,我可以随意添加任何我想要的东西。 我什至加了水印!

    希望这对人们有所帮助!

    //component that has the div i need pdf'ed
    //
    
    var reactToPdfUtils = require('../../../../../reactToPdf.js');
    
        const handleSave = (sourceElement) => {
            console.log('handleSave in SFV!');
            reactToPdfUtils.useSavePDFNOW(pdfProps, cb, sourceElement)
            function cb(sendDataContent){   
                console.log(sendDataContent)
            }
        };
        
    //////////////////////////////////////////////////////////////////////////////////////////////
    
    
    
    //reactToPdf.js      file that houses the library function I manipulate to get the result
    
    
    import React, { useEffect } from 'react';
    import { savePDF } from '@progress/kendo-react-pdf';
    import { drawDOM, exportPDF } from '@progress/kendo-drawing';
    
    export const useSavePDFNOW = (pdfProps, cb, sourceElement) => {
        //pdfprops i pass in from meta data in my mongoDB, 
        //I made a cb to let me know when the funtion is done
        //I also do elaborate checking here myself for example
        //to make sure there is only one div that that id 
       
            //create a template
            //this function is declared then passed in later to savePDF, 
            //the magic in the library allows    you to manipulate each page if you wanted. You can do some         //cool stuff here.
     try {
            const onEveryPage = (props) => {
                if (hasAfirstPage) {
                    if (props.pageNum === 1) {
                        document.querySelectorAll('#toPDF')[0].style.cssText = 'margin-top: -188.333px;height:100%;';
                        // document.querySelectorAll('kendo-pdf-page')[0].style.cssText = '';
                        return <Fragment></Fragment>;
                    } else {
                        return (
                            <div style={{ zIndex: '-999999', justifyContent: 'center', display: 'flex' }}>
                                <div id='header' style={{ textAlign: 'center', fontSize: headerFontToUse + 'px', backgroundRepeat: 'no-repeat', backgroundSize: '100%', backgroundColor: 'transparent', height: headerHeightToUse, width: headerWidthToUse, backgroundImage: `url(${headerSrcToUse})`, position: 'absolute', top: 10 }}>
                                    {headerTextToUse}
                                </div>
                                <div id='watermarkImage' style={{ backgroundRepeat: 'no-repeat', backgroundSize: '100%', backgroundColor: 'transparent', height: waterMarkHeightToUse, width: headerWidthToUse, opacity: 0.5 /* Firefox, Chrome, Safari, Opera, IE >= 9 (preview) */, backgroundImage: `url(${waterMarkSrcToUse})`, position: 'absolute', bottom: -90, left: 300 }}></div>
                                <div id='pageNums' style={{ position: 'absolute', bottom: 0, right: '10px' }}>
                                    Page {props.pageNum} of {props.totalPages}
                                </div>
                                <h6 id='footer' style={{ fontSize: footerFontToUse + 'px', backgroundColor: 'transparent', position: 'absolute', bottom: 0, margin: '6 auto' }}>
                                    {footerTextToUse}
                                </h6>
                            </div>
                        );
                    }
                } else {
                    return (
                        <div style={{ zIndex: '-999999', justifyContent: 'center', display: 'flex' }}>
                            <div id='header' style={{ textAlign: 'center', fontSize: headerFontToUse + 'px', backgroundRepeat: 'no-repeat', backgroundSize: '100%', backgroundColor: 'transparent', height: headerHeightToUse, width: headerWidthToUse, backgroundImage: `url(${headerSrcToUse})`, position: 'absolute', top: 10 }}>
                                {headerTextToUse}
                            </div>
                            <div id='watermarkImage' style={{ backgroundRepeat: 'no-repeat', backgroundSize: '100%', backgroundColor: 'transparent', height: waterMarkHeightToUse, width: headerWidthToUse, opacity: 0.5 /* Firefox, Chrome, Safari, Opera, IE >= 9 (preview) */, backgroundImage: `url(${waterMarkSrcToUse})`, position: 'absolute', bottom: -90, left: 300 }}></div>
                            <div id='pageNums' style={{ position: 'absolute', bottom: 0, right: '10px' }}>
                                Page {props.pageNum} of {props.totalPages}
                            </div>
                            <h6 id='footer' style={{ fontSize: footerFontToUse + 'px', backgroundColor: 'transparent', position: 'absolute', bottom: 0, margin: '6 auto' }}>
                                {footerTextToUse}
                            </h6>
                        </div>
                    );
                }
            };
            //MaterialUI font fixing may have to do this elsewhere too specific
            parentWrapper.querySelectorAll('[class*=MuiTypography], [class*=Text], [class*=formControl]').forEach(function (el, i) {
                el.setAttribute('style', 'color: black; overflow: visible');
            });
    
            //save pdf on client side, send blob to dev to figure out what he or she wants to do with it
            let pdfBlob;
            savePDF(
                parentWrapper,
                {
                    pageTemplate: onEveryPage,
                    paperSize: 'a4',
                    fileName: 'Testing',
                    keepTogether: '.menu',
                    scale: 0.6,
                    title: 'Ametek/Powervar Passport',
                    margin: { top: marginTopToUse, bottom: marginBottomToUse }
                },
                () => {
                    // Server side rendering tested comes out exactly the same so long as the props match
                    drawDOM(parentWrapper, { pageTemplate: onEveryPage, scale: 0.6, paperSize: 'A4', margin: { top: 180, bottom: 10 } })
                        .then((group) => {
                            return exportPDF(group);
                        })
                        .then((dataUri) => {
                            // Send action to database
                            pdfBlob = dataUri.split(';base64,')[1];
                            ClassInstancesActions.StorePassportPDFToDisk(pdfBlob, 'testing');
                            cb(pdfBlob);
                            parentWrapper.remove();
                        });
                }
            );
        } catch (error) {
            console.log(error);
        }
    };
    //This is in a style sheet
    //i have a div within the div I pdf with an id of #divToDisableInteraction
    //As long as there in there you can do any css magic to your pdf document here
    //I tested this to high heaven you can get most things done here
    //including adding an image url
    
    
    kendo-pdf-document #divToDisableInteraction {
        visibility: hidden;
      }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-17
      • 2020-10-28
      • 1970-01-01
      • 1970-01-01
      • 2018-10-08
      • 2023-03-07
      • 2020-01-02
      • 2017-01-31
      相关资源
      最近更新 更多