jspdf & html2canvas 导出pdf(所见即所得)

5 篇文章 0 订阅

jspdf & html2canvas 导出pdf(所见即所得)

  • 引入html2canvas
    import html2canvas from "html2canvas";
  • 引入jsPDF
    import jsPDF from "jspdf";
  • 分不同状况使用,如下:

一、完全不分页

const container = 要导出的div;
// 将html转为canvas
html2canvas(container, {
  allowTaint: true,
  useCORS: true, // 允许图片跨域,不开启这项的话会导致图片无法下载
  scale: 2, 
  dpi: "192"
}).then(canvas => {
    const { width, height } = canvas;
    const url = canvas.toDataURL("image/jpeg", 1.0); // 将canvas转为url
    const pdfWidth = (width / 2) * 0.75; // 计算pdf的宽度
    const pdfHeight = (height / 2) * 0.75; // 计算pdf的高度
    const displayWidth = pdfWidth;
    const displayHeight = (height / 2) * 0.75;
    const pdf = new jsPDF("", "pt", [pdfWidth, pdfHeight]); // 生成pdfWidth宽、pdfHeight高的pdf
    pdf.addImage(url, "jpeg", 0, 0, displayWidth, displayHeight); // 将图片写入pdf中
    pdf.save(`${自定义文件名}.pdf`);
});

二、超过A4纸高度直接分页(为了打印)

const container = 要导出的div;
html2canvas(container, {
  allowTaint: true,
  useCORS: true,
  scale: 2,
  dpi: "192"
}).then(canvas => {
   const { width, height } = canvas;
   // 一页pdf显示html页面生成的canvas高度;
   const pageHeight = (width / 592.28) * 841.89;
   // 未生成pdf的html页面高度
   let leftHeight = height;
   //页面偏移
   var position = 0;
   // a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
   const imgWidth = 595.28;
   const imgHeight = (592.28 / width) * height;

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

   const pdf = new jsPDF("", "pt", "a4");

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

三、超过A4纸高度动态分页

const A4_WIDTH = 595.28; // A4纸宽度
const A4_HEIGHT = 841.89; // A4纸高度
// 分割页面函数
// 最小单位的class  => minimum-unit
dividePage (dom) {
  const pageOffsetTop = dom.offsetTop; // 获取当前dom相对top
  const pageOffsetWidth = dom.offsetWidth; // 获取当前dom的宽度
  const unitDoms = dom.querySelectorAll('.minimum-unit'); // 获取所有的最小单位的子元素

  const perPageHeight = pageOffsetWidth / A4_WIDTH * A4_HEIGHT; // 一页pdf显示html页面生成的canvas高度

  const pages = [
    [
      { // 起点初始化
        top: 0, // 当前元素的底部距离dom最顶点的距离
        offsetTop: 0 // 当前元素的顶部距离dom最顶点的距离,用来做分割的位置信息
      }
    ]
  ]

  // 遍历最小单元格
  // 获取单元格底部距离顶部的高度 top,以及 offsetTop
  // 根据 top 值,算出该单元格的页码,放入数组 pages
  unitDoms.forEach(item => {
    const offsetTop = item.offsetTop - pageOffsetTop; // 计算距离dom最顶点的距离
    const top = offsetTop + item.offsetHeight; // 计算当前元素的底部距离dom最顶点的距离,用来判断元素放在哪一页的依据
    const pageIndex = parseInt(top / perPageHeight); // 算出当前元素的页码

    // 若还未有此页码,则新开一页
    if (!pages[pageIndex]) {
      pages[pageIndex] = []
    }
	
	// 当前元素放入对应页码中
    pages[pageIndex].push({
      top,
      offsetTop
    })
  });
  return pages;
}

 handleDownload () {
  const container = 要导出的div;
  const scale = 2; // 放大的倍数
  html2canvas(container, {
    allowTaint: true,
    useCORS: true,
    scale,
    dpi: "192"
  })
    .then(canvas => {
      const { width, height } = canvas;
      const imgHeight = (A4_WIDTH / width) * height;
      const img = new Image();
      img.src = canvas.toDataURL("image/png", 1.0);
      img.onload = () => {
        const pages = this.dividePage(container, height); // 分页
        const pdf = new jsPDF("", "pt", "a4");
        pages.forEach((page, index) => {
          const { offsetTop } = page[0]; // 获取分割位置
          const { top } = page[page.length - 1]; // 获取当前页最末尾的位置
          const previewCanvas = document.createElement('canvas'); // 获取备用画布, 分割图片
          
          // 必须设定宽高,不然会有默认宽高,导致显示的内容不对
          previewCanvas.width = width; // html2canvas返回的canvas的宽度
          previewCanvas.height = height; // html2canvas返回的canvas的高度
          
          const previewCtx = previewCanvas.getContext("2d");
        
          previewCtx.drawImage(img, 0, offsetTop * scale, width, (top - offsetTop) * scale, 0, 0, width, (top - offsetTop) * scale); // 截取指定范围内的图片
          previewCtx.putImageData(previewCtx.getImageData(0, 0, width, (top - offsetTop) * scale), 0, 0); // 将图片传至canvas中,以便转化为dataurl

		  // 给previewCanvas不足的完整高度的部分设置底色
          previewCtx.fillStyle = 'rgba(255,255,255,1)'; 
          previewCtx.fillRect(0, (top - offsetTop) * scale, previewCanvas.width, previewCanvas.height - ((top - offsetTop) * scale));
          const pageData = previewCanvas.toDataURL("image/jpeg", 1.0);
		  // 当需要分页的时候,添加分页
          if (index > 0) {
            pdf.addPage()
          }
          pdf.addImage(pageData, 'JPEG', 0, 0, A4_WIDTH, imgHeight); // 对应截好的图写入pdf中
        })
        pdf.save(`${自定义文件名}.pdf`);
      }
    })
}
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值