react页面指定dom转pdf导出

1. 使用jsPDF+html2canvas将页面转成图片然后导出

缺点:页面过长可能会导出失败,并且由于电脑分辨率的问题导致导出文件模糊不清

实现代码:

import jsPDF from 'jspdf';
import html2canvas from 'html2canvas';

export function downToPdf(className: string, name: string) {
  let elements = document.getElementsByClassName(className); // 获取指定类名的元素
  if (elements.length === 0) {
    return;
  }
  let element: any = elements[0]; // 使用第一个匹配到的元素
  let w = element.offsetWidth; // 获取容器的宽度
  let h = element.offsetHeight; // 获取容器的高度
  let canvas = document.createElement("canvas");
  canvas.width = w;
  canvas.height = h;
  // 默认横向没有滚动条的情况,因为offsetLeft有无滚动条的时候存在差值,因此
  // translate的时候,要把这个差值去掉
  html2canvas(element, {  // 设置option可去除灰色色块
    allowTaint: false,
    useCORS: true,
    scale: 1.2, // 用于渲染的比例。默认为浏览器设备像素比率
    backgroundColor: '#F5F5F5',
    windowWidth: element.scrollWidth,
    windowHeight: element.scrollHeight
  }).then(function (canvas) {
    let contentWidth = canvas.width;
    let contentHeight = canvas.height;
    // 一页pdf显示html页面生成的canvas高度
    let pageHeight = (contentWidth / 592.28) * 841.89;
    // 未生成pdf的html页面高度
    let leftHeight = contentHeight;
    // 页面偏移
    let position = 0;
    // a4纸的尺寸[595.28,841.89]pt,html页面生成的canvas在pdf中图片的宽高
    let imgWidth = 595.28;
    let imgHeight = (592.28 / contentWidth) * contentHeight - 56.7;  // 上下边距10mm

    let pageData = canvas.toDataURL("image/jpeg", 1.0);

    let pdf = new jsPDF("p", "pt", "a4");

    // 有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
    // 当内容未超过pdf一页显示的范围,无需分页
    if (leftHeight < pageHeight) {
      pdf.addImage(pageData, "JPEG", 0, 28.35, imgWidth, imgHeight);
    } else {
      // 分页
      while (leftHeight > 0) {
        pdf.addImage(pageData, "JPEG", 0, position + 28.35, imgWidth, imgHeight);
        leftHeight -= pageHeight; // 加上页面高度和上下的页面距
        position -= 841.89;
        // 避免添加空白页
        if (leftHeight > 0) {
          pdf.addPage();
        }
      }
    }
    pdf.save(name + ".pdf");
  });
}

2. 自定义创建iframe调用iframe.print()进行页面打印转pdf导出

缺点:对于echarts图表可能出现样式问题

代码实现:

export const printPDF = (dom: any) => {
  // 将canvas元素转换为图片
  convertCanvasToImages(dom);
};

// 写入iframe
function writeIframe(dom: any) {
  const iframe: any = document.createElement("iframe");
  iframe.style.position = "absolute";
  iframe.style.width = "0";
  iframe.style.height = "0";
  iframe.style.top = "-10px";
  iframe.style.left = "-10px";
  document.body.appendChild(iframe);
  const doc: any = iframe.contentDocument;

  doc.open();
  doc.write(getStyle() + getHtml(dom));
  doc.close();

  iframe.onload = function () {
    iframe.contentWindow.print();

    setTimeout(() => {
      document.body.removeChild(iframe);
    }, 100);
  };
}

// 获取样式
function getStyle() {
  const styles = document.querySelectorAll("style,link");
  let str = "";

  for (let i = 0; i < styles.length; i++) {
    str += styles[i].outerHTML;
  }
  str += `<style>
    @media print {
      html,body{
        height: auto;
        margin: 0;
      }
      body{
        zoom: 100%;
      }
      img{
        max-width: 100% !important;
        height: auto !important;
        page-break-inside: auto;
        break-inside: auto;
      }
      @page {
        margin: 0;
      }
    }
  </style>`;
  return str;
}

// 获取dom
function getHtml(dom: any) {
  return dom.outerHTML;
}

// 将canvas元素转换为图片
function convertCanvasToImages(dom: any) {
  const canvasElements = dom.querySelectorAll('canvas');
  let convertedCount = 0;

  if (canvasElements.length === 0) {
    writeIframe(dom);
    return;
  }

  canvasElements.forEach((canvas: any) => {
    const img = document.createElement('img');
    img.src = canvas.toDataURL('image/png');
    img.style.width = '100%';
    img.style.height = 'auto';
    canvas.parentNode.replaceChild(img, canvas);

    convertedCount++;
    if (convertedCount === canvasElements.length) {
      writeIframe(dom);
    }
  });
}

3. 使用react-to-print插件打印pdf

缺点:对于大量echarts图表可能会随机几个出现样式问题

代码实现:

  1. 下载: yarn add react-to-print
  2. 引入插件

import {useReactToPrint} from “react-to-print”;

  1. 使用
import React, { useRef } from 'react';
import { useReactToPrint } from 'react-to-print';

const PrintComponent = React.forwardRef((props, ref) => {
  return (
    <div ref={ref} style={{ width: '100%', height: 'auto' }}>
      {/* 你的长内容 */}
      <div>Page 1</div>
      <div>Page 2</div>
      <div>Page 3</div>
      {/* 更多内容 */}
    </div>
  );
});

const App = () => {
  const printRef = useRef();

  // 打印功能
  const handlePrint = useReactToPrint({
    content: () => printRef.current,
    pageStyle: `
      @page {
        size: A4;
        margin: 0;
      }
      @media print {
        body, html {
          height: auto;
          overflow: initial !important;  // 重要,如果不分页需要加上
          margin: 0;
        }
        body{
          zoom: 100%;
        }
        img{
          max-width: 100% !important;
          height: auto !important;
          page-break-inside: auto;
          break-inside: auto;
        }
      }`,
    removeAfterPrint: true,
    documentTitle: `报告名称`,
  });

  return (
    <div>
      <PrintComponent ref={printRef} />
      <button onClick={handlePrint}>打印</button>
    </div>
  );
};

export default App;

相关推荐

  1. react页面指定dompdf导出

    2024-07-18 09:42:02       20 阅读
  2. Reactreact-router-dom路由导航的跳及传参

    2024-07-18 09:42:02       59 阅读
  3. Aspose将doc,pptpdf

    2024-07-18 09:42:02       23 阅读
  4. 使用 React Router Dom 实现路由导航

    2024-07-18 09:42:02       37 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-18 09:42:02       66 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-18 09:42:02       70 阅读
  3. 在Django里面运行非项目文件

    2024-07-18 09:42:02       57 阅读
  4. Python语言-面向对象

    2024-07-18 09:42:02       68 阅读

热门阅读

  1. 树莓派docker安装lnmp

    2024-07-18 09:42:02       18 阅读
  2. 人像视频预处理v1.2 优化检测、处理速度

    2024-07-18 09:42:02       22 阅读
  3. c++ extern 关键字

    2024-07-18 09:42:02       22 阅读
  4. 【C++】C++ 文件模式标志

    2024-07-18 09:42:02       23 阅读
  5. nginx域名跳转到另一个域名

    2024-07-18 09:42:02       22 阅读
  6. ios 设置行距和获取文本行数

    2024-07-18 09:42:02       21 阅读
  7. (86)组合环路--->(01)RGB值

    2024-07-18 09:42:02       18 阅读
  8. 详细说一下axios的特点

    2024-07-18 09:42:02       22 阅读
  9. log4j.appender.Logfile.File=./logs/its_log

    2024-07-18 09:42:02       20 阅读