使用React+html2canvas + jspdf实现生成pdf文件

1. 安装插件

先安装第一个html2canvas插件,作用是实现将html页面转换成图片

安装命令如下:

npm install --save html2canvas || npm install html2canvas

然后安装第二个插件jspdf,作用是将图片转为pdf

安装命令如下:

npm install jspdf --save || npm install jspdf

2. 导入html2canvas和jspdf插件到项目中

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

3. 定义一个div和需要生成pdf的页面 (或者给需要到处的页面元素最外层加id)

<div id="demo">
  <div style={{marginTop:15}}>
    <div>
    	此为到处的pdf文件
    </div>
  </div>
</div>

4. 定义一个触发生成pdf文件的按钮

<Button onClick={download}>生成报告</Button>

5. 实现download方法之一

download = () => {
  const element = document.getElementById('demo');  // 这个dom元素是要导出的pdf的div容器
  const w = element.offsetWidth;  // 获得该容器的宽
	const h = element.offsetHeight;  // 获得该容器的高
  const offsetTop = element.offsetTop; // 获得该容器到文档顶部的距离  
  const offsetLeft = element.offsetLeft; // 获得该容器到文档最左的距离
  const canvas = document.creatElement("canvas");
  let abs = 0;
  const win_i = document.body.clientWidth; // 获得当前可视窗口的宽度(不包含滚动条)
  const win_o = window.innerWidth; // 获得当前窗口的宽度(包含滚动条)
  if(win_o > win_i){
    abs = (win_o - win_i) / 2; // 获得滚动条宽度的一半
  }
	canvas.width = w * 2; // 将画布宽&&高放大两倍
  canvas.height = h * 2;
  const context = canvas.getContext('2d');
  context.scale(2, 2);
  context.translate(-offsetLeft - abs, -offsetTop);
  // 这里默认横向没有滚动条的情况,因为offset.left(),有无滚动条的时候存在差值,因此translate的时候,要把这个差值去掉
  html2canvas(element, {
    allowTaint: true,
    scale: 2 // 提升画面质量,但是会增加文件大小
  }).then( canvas => {
    const contentWidth = canvas.width;
    const contentHeight = canvas.height;
    // 一页pdf显示html页面生成的canvas高度
    const pageHeight = contentWidth / 592.28 * 841.89;
    // 未生成pdf的html页面高度
    const leftHeight = contentHeight;
    // 页面偏移
    const position = 0;
    // a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
    const imgWidth = 595.28;
    const imgHeight = 592.28 / contentWidth * contentHeight;
    
    const pageDate = canvas.toDataURL('image/jpeg', 1.0);
    
    const pdf = new jsPDF('', 'pt', 'a4');
    // 有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面的高度(841.89)
    // 当内容未超过pdf一页显示的范围,无需分页
    if(leftHeight < pageHeight) {
      pdf.addImage(pageDate,'JPEG', 0, position, imgWidth, imgHeight);
    }else { // 分页
      while (leftHeight > 0){
          pdf.addImage(pageDate, 'JPEG', 0, position, imgWidth, imgHeight) 
        	leftHeight -= pageHeight;
        	position -= 841.89;
        	// 避免添加空白页
        	if(leftHeight > 0){
            pdf.addPage()
          }
      }
    }
    
    pdf.save('你的名字.pdf');    
  })
    
}

方法二:

download = () => {
    const element = document.getElementById('demo');
    const imgHeight = element.clientHeight;
    const imgWidth = element.clientWidth;
    const scale = 3;
    html2canvas(element, {
      letterRendering: true,
      allowTaint: true,
      taintTest: false,
      height: imgHeight,
      //  为了使横向滚动条的内容全部展示,这里必须指定
      width: imgWidth,
      backgroundColor: '#fff',
      scale: scale, // 提升画面质量,但是会增加文件大小,
      onclone: (element) => {
       const inputs =  element.getElementsByTagName("input")
       let inputList = Array.prototype.slice.call(inputs);
       inputList.map((item)=>{
         if(item.placeholder){
           item.removeAttribute("placeholder")
         }
       })
       let selectHolder = detail.querySelectorAll(".ant-select-selection-placeholder")
       let selectHolderList = Array.prototype.slice.call(selectHolder)
       selectHolderList.map((item)=>{
         item.style.display = "none"
       })
        // detail.getElementById("campaignInfo_targetGroupDescription").removeAttribute("placeholder")
        // onclone logic to resize div
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve()
            },500)
        })
      }
  }).then((canvas) => {
    const pageData = canvas.toDataURL('image/jpeg', 1);
      // 设置pdf的尺寸,pdf要使用pt单位 已知 1pt/1px = 0.75   pt = (px/scale)* 0.75
      // scale为上面的scale 缩放了scale倍, 60为pdf四周留白
      let pdfX = (imgWidth + 60) / scale * 0.75
      let pdfY = (imgHeight + 60) / scale * 0.75  
      let imgX = (imgWidth / scale * 0.75)
      let imgY = (imgHeight / scale * 0.75); //内容图片这里不需要留白的距离
      // pdfX,pdfY为pdf的大小,imgX,imgY为内容图片的大小
      let PDF = new jsPDF('', 'pt', [pdfX, pdfY])
      // 7.5 为坐标,让img在pdf中水平垂直居中,四周留白均匀
      PDF.addImage(pageData, 'JPEG', 7.5, 7.5, imgX, imgY);
      //获取当前时间戳
      let timestmp = new Date().getTime()
      PDF.save(`cmt_campaign_basic_info_${lib.dataFormat(timestmp)}.pdf`);
      this.campaignDetailStore.pdfLoadingVisible = false
      // this.setState({
      //   pdfimg:pageData
      // })
  }).catch(() => {
    this.campaignDetailStore.pdfLoadingVisible = false
    // this.setState({ exportPDF: false });
  	});
 };
posted @ 2021-04-30 17:13  春燕啄春泥  阅读(2654)  评论(2编辑  收藏  举报