html2canvas+jspdf生成PDF

1、安装 html2canvas 和 jspdf :

npm install html2canvas

npm install jspdf

2、按A4纸标准生成PDF(同内容块不裁剪分页):

1)引入 html2canvasjspdf

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

2)下载按钮点击前用延迟函数等待页面渲染完成:

setStateFun = () => {
    const _this = this;
    let creatPdfTimer=window.setTimeout(_this.creatPdf,500);
    _this.setState({
      creatPdfTimer,
    })
}

3)生成PDF:

creatPdf = () => {
    const _this = this;
    html2canvas(this.standardPlanpdfs,{//把此dom节点下的内容生成pdf
      dpi: 192,
      scale: 2,
      useCORS: true,
      async: false,//同步执行
    }).then(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 = 64;
      let position = 0;
      //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
      let a4Width = 595.28
      let a4Height = 841.89 //A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
      //一页pdf显示html页面生成的canvas高度;
      let a4HeightRef = Math.floor((canvas.width / a4Width) * a4Height)
      let pageData = canvas.toDataURL('image/jpeg', 1.0);
      let pdf = new jsPDF('', 'pt', 'a4') //A4纸,纵向
      let index = 1,
      canvas1 = document.createElement('canvas'),
      height;
      pdf.setDisplayMode('fullwidth', 'continuous', 'FullScreen')

      let pdfName = "standardPlan.pdf";
      if(_this.state.name&&_this.state.grade&&_this.state.grade.name){
        pdfName = `${_this.state.grade.name}-${_this.state.name}.pdf`;
      }else if(_this.state.name){
        pdfName = `${_this.state.name}.pdf`;
      }
      function createImpl(canvas) {
        if (leftHeight > 0) {
          index++
  
          let checkCount = 0
          if (leftHeight > a4HeightRef) {
            let i = position + a4HeightRef;
            for (i = position + a4HeightRef; i >= position; i--) {
              let isWrite = true
              for (let j = 0; j < canvas.width; j++) {
                let c = canvas.getContext('2d').getImageData(j, i, 1, 1).data;
                if (c[0] != 0xff || c[1] != 0xff || c[2] != 0xff) {
                  isWrite = false
                  break
                }
              }
              if (isWrite) {
                checkCount++
                if (checkCount >= 20) {
                  break
                }
              } else {
                checkCount = 0
              }
            }
            height = Math.round(i - position) || Math.min(leftHeight, a4HeightRef);
            if (height <= 0) {
              height = a4HeightRef
            }
          } else {
            height = leftHeight
          }
  
          canvas1.width = canvas.width
          canvas1.height = height
  
          let ctx = canvas1.getContext('2d')
          ctx.drawImage(
            canvas,
            0,
            position,
            canvas.width,
            // a4Width,
            height,
            0,
            0,
            canvas.width,
            // a4Width,
            height,
          )
  
          let pageHeight = Math.round((a4Width / canvas.width) * height)
          // pdf.setPageSize(null, pageHeight)
          if (position != 0) {
            pdf.addPage()
          }
          pdf.addImage(
            canvas1.toDataURL('image/jpeg', 1.0),
            'JPEG',
            // 32,//左侧边距
            28,//左侧边距
            // 0,
            32,//头部边距
            a4Width - 64,
            // a4Width,
            (a4Width / canvas1.width) * height - 64,
          )
          leftHeight -= height
          position += height
          if (leftHeight > 0) {
            setTimeout(createImpl, 500, canvas)
          }
          else {
            pdf.save(pdfName);
            _this.setState({
              downloadLoading:false,
            });
          }
        }
      }
      //当内容未超过pdf一页显示的范围,无需分页
      if (leftHeight < a4HeightRef) {
        pdf.addImage(
          pageData,
          'JPEG',
          // 32,//左侧边距
          28,//左侧边距
          // 0,
          32,//头部边距
          a4Width - 64,
          // a4Width,
          (a4Width / canvas.width) * leftHeight - 64,
        )
        pdf.save(pdfName);
        _this.setState({
          downloadLoading:false,
        });
      } else {
        try {
          pdf.deletePage(0);
          setTimeout(createImpl, 500, canvas);
        } catch (err) {
          // console.log(err);
        }
      }
  }

3、按页面标准生成PDF(内容过长时:同内容块不裁剪分页--根据颜色进行裁剪):

creatPdf = () => {
    const { reportData } = this.state;
    const _this = this;
    html2canvas(this.fitnessReportClasss,{//把此dom节点下的内容生成pdf
      allowTaint: true,
      taintTest: false,
      // dpi: window.devicePixelRatio,
      dpi: 120,
      useCORS: true,
      // background: '#FFFFFF',
    }).then(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 = 64;
      let position = 0;
      //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
      let a4Width = 595.28
      let a4Height = 841.89 //A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
      //一页pdf显示html页面生成的canvas高度;
      let a4HeightRef = Math.floor((canvas.width / a4Width) * a4Height)
      let pageData = canvas.toDataURL('image/jpeg', 1.0);
      let pdf = new jsPDF('p', 'pt', 'a4') //A4纸,纵向
      let index = 1,
      canvas1 = document.createElement('canvas'),
      height;
      pdf.setDisplayMode('fullwidth', 'continuous', 'FullScreen')

      let pdfName = reportData && reportData.schoolName && reportData.classesName?
        reportData.schoolName+' '+reportData.classesName+'-报告':'fitnessReportClass';
      function createImpl(canvas) {
        if (leftHeight > 0) {
          index++
  
          let checkCount = 0
          if (leftHeight > a4HeightRef) {
            let i = position + a4HeightRef;
            for (i = position + a4HeightRef; i >= position; i--) {
              let isWrite = true
              for (let j = 0; j < canvas.width; j++) {
                let c = canvas.getContext('2d').getImageData(j, i, 1, 1).data;
                if (c[0] != 0xff || c[1] != 0xff || c[2] != 0xff) {
                  isWrite = false
                  break
                }
              }
              if (isWrite) {
                checkCount++
                if (checkCount >= 20) {
                  break
                }
              } else {
                checkCount = 0
              }
            }
            height = Math.round(i - position) || Math.min(leftHeight, a4HeightRef);
            if (height <= 0) {
              height = a4HeightRef
            }
          } else {
            height = leftHeight
          }
  
          canvas1.width = canvas.width
          canvas1.height = height
  
          let ctx = canvas1.getContext('2d')
          ctx.drawImage(
            canvas,
            0,
            position,
            canvas.width,
            height,
            0,
            0,
            canvas.width,
            height,
          )
  
          let pageHeight = Math.round((a4Width / canvas.width) * height)
          if (position != 0) {
            pdf.addPage()
          }
          pdf.addImage(
            canvas1.toDataURL('image/jpeg', 1.0),
            'JPEG',
            32,
            32,
            a4Width - 64,
            (a4Width / canvas1.width) * height - 64,
          )
          leftHeight -= height
          position += height
          if (leftHeight > 0) {
            setTimeout(createImpl, 500, canvas)
          } else {
            pdf.save(pdfName + '.pdf');
            _this.setState({
              downloadLoading:false,
            });
          }
        }
      }
      //当内容未超过pdf一页显示的范围,无需分页
      if (leftHeight < a4HeightRef) {
        pdf.addImage(
          pageData,
          'JPEG',
          32,
          32,
          a4Width - 64,
          (a4Width / canvas.width) * leftHeight - 64,
        )
        pdf.save(pdfName + '.pdf');
        _this.setState({
          downloadLoading:false,
        });
      } else {
        try {
          pdf.deletePage(0);
          setTimeout(createImpl, 500, canvas);
        } catch (err) {
          // console.log(err);
        }
      }
    })
  }

4、生成一页PDF(内容不超长):

creatPdf = () => {
    const {evaluation_report: {data},} = this.props;
    const _this = this;
    // 这里默认横向没有滚动条的情况,因为offset.left(),有无滚动条的时候存在差值,因此
    // translate的时候,要把这个差值去掉
    html2canvas(this.classReportpdfs,{//把此dom节点下的内容生成pdf
      allowTaint: true,
      dpi: window.devicePixelRatio,
      useCORS: true,
    }).then(canvas=>{
      let element = document.getElementById("classReportOne");    // 这个dom元素是要导出pdf的div容器
      let w = element.offsetWidth;    // 获得该容器的宽
      let h = element.offsetHeight;    // 获得该容器的高
      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 = 64;
      // let position = 0;
      //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
      // let imgWidth = 560.28;
      let imgWidth = 595.28;
      let imgHeight = 592.28/contentWidth * contentHeight;
      let pageData = canvas.toDataURL('image/jpeg', 1.0);
      let pdf = new jsPDF('', 'pt', [contentWidth, contentHeight]);
      pdf.addImage(pageData, 'JPEG', 48, position, contentWidth-96, contentHeight-128 );
      //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
      //当内容未超过pdf一页显示的范围,无需分页
      if(data.hvgData && data.hvgData.schoolName && data.hvgData.classesName){
        pdf.save(`${data.hvgData.schoolName+' '+data.hvgData.classesName}.pdf`);
        _this.setState({
          downloadLoading:false,
        });
      }else{
        pdf.save("classReport.pdf");
        _this.setState({
          downloadLoading:false,
        });
      }
      // pdf.save("creat.pdf");
    })
  }

注:插件参数请参考对应官网

原文地址:https://www.cnblogs.com/dreambin/p/15329603.html