前端打印、生成PDF的那些事

前端打印、生成PDF的那些事

概要

最近项目中经常做到前端打印、生成PDF功能这篇文章主要是记录下遇到的问题、以及实现方案

使用到的库

  • html2canvas
    npm i html2canvas
    yarn add html2canvas
  • jspdf
    npm i jspdf
    yarn add jspdf
  • print-js
    npm i print-js
    yarn add print-js

打印

这个功能我们使用到print-js库来实现

javascript 复制代码
print({
	 printable: 'print-template',//需要打印的元素id
     type: "html",// 打印内容的类型
     targetStyles: ["*"],
     scanStyles: false, // 保留样式、这里需要设置为false
     style: getPrintStyle(), // 此处接受一个 css 样式字符串
})
// 将scanStyles 设置为 false 是为了更好的解决打印时出现的内容被截断的问题、此处设置为false,然后我们就可以自己写样式来定义打印模板的展示方式。

//style 的值我们可以写一个函数返回
const getPrintStyle =() => {
	return `
		#print-template {
	        font-weight: 400;
	        font-size: 12px;
	    }
	    table td {
	        padding: 8px;
	    }
	    table th {
	        white-space: nowrap;
	        padding: 8px;
	    }
	    table tr {
	        page-break-inside: avoid;
	    }
	    #print-template .date {
	        padding-bottom: 12px;
	        font-weight: 600;
	    }`
}

使用上述的方式就能解决打印内容被截断的问题了。

生成PDF

这个功能我们使用到html2canvas 和 jspdf库来实现

实现思路:将需要生成PDF的DOM节点使用html2canvas 生成 canvas 再使用 canvas.toDataURL 方法将 canvas转成图片base64、然后使用 jspdf 的 addImage方法将图片base64 转成PDF。

将二者一起封装成方法:如下

javascript 复制代码
const generatePDF = (selector: string, fileName: string) => {
    const element: any = document.querySelector(selector);
    const opts = {
      scale: 12, // 缩放比例,提高生成图片清晰度
      useCORS: true, // 允许加载跨域的图片
      allowTaint: false, // 允许图片跨域,和 useCORS 二者不可共同使用
      tainttest: true, // 检测每张图片已经加载完成
      logging: true // 日志开关,发布的时候记得改成 false
    };

    return html2Canvas(element, opts)
      .then(canvas => {
        const contentWidth = canvas.width;
        const contentHeight = canvas.height;
        // 一页pdf显示html页面生成的canvas高度;
        const pageHeight = (contentWidth / 592.28) * 841.89;
        // 未生成pdf的html页面高度
        let leftHeight = contentHeight;
        // 页面偏移
        let position = 0;
        // a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
        const imgWidth = 595.28;
        const imgHeight = (592.28 / contentWidth) * contentHeight;
        const pageData = canvas.toDataURL("image/jpeg", 1.0);

        // a4纸纵向,一般默认使用;new JsPDF('landscape'); 横向页面
        const PDF = new JsPDF(undefined, "pt", "a4");
        // 当内容未超过pdf一页显示的范围,无需分页
        if (leftHeight < pageHeight) {
          // addImage(pageData, 'JPEG', 左,上,宽度,高度)设置
          PDF.addImage(pageData, "JPEG", 0, 0, imgWidth, imgHeight);
        } else {
          // 超过一页时,分页打印(每页高度841.89)
          while (leftHeight > 0) {
            PDF.addImage(pageData, "JPEG", 0, position, imgWidth, imgHeight);
            leftHeight -= pageHeight;
            position -= 841.89;
            if (leftHeight > 0) {
              PDF.addPage();
            }
          }
        }
        PDF.save(fileName + ".pdf");
      })
      .catch(error => {
        console.log("打印失败", error);
      });
  };

调用:generatePDF('元素选择器', '导出的PDF文件名')

小结

1.上述导出PDF的功能还有一些问题没有完善、例如如果内容时table表格 的时候需要精准计算每一行的高度、再进行计算最终动态改变position偏移量来解决table内容被截断的问题。后续有空补上这部分代码。

相关推荐
大猫会长13 小时前
tailwindcss中,自定义多个背景渐变色
前端·html
xj75730653313 小时前
《python web开发 测试驱动方法》
开发语言·前端·python
IT=>小脑虎13 小时前
2026年 Vue3 零基础小白入门知识点【基础完整版 · 通俗易懂 条理清晰】
前端·vue.js·状态模式
IT_陈寒13 小时前
Python 3.12性能优化实战:5个让你的代码提速30%的新特性
前端·人工智能·后端
赛博切图仔13 小时前
「从零到一」我用 Node BFF 手撸一个 Vue3 SSR 项目(附源码)
前端·javascript·vue.js
爱写程序的小高13 小时前
npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree
前端·npm·node.js
loonggg13 小时前
竖屏,其实是程序员的一个集体误解
前端·后端·程序员
winfredzhang14 小时前
从零构建:手写一个支持“高度定制化排版”的 Chrome 网页摘录插件
chrome·pdf·插件·epub·零碎信息归档
程序员爱钓鱼14 小时前
Node.js 编程实战:测试与调试 - 单元测试与集成测试
前端·后端·node.js
码界奇点14 小时前
基于Vue.js与Element UI的后台管理系统设计与实现
前端·vue.js·ui·毕业设计·源代码管理