前端打印、生成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内容被截断的问题。后续有空补上这部分代码。

相关推荐
To_OC1 小时前
别再串行写 await 了,Promise.all 才是并行请求的正确打开方式
前端·javascript·promise
vipbic2 小时前
中后台越做越乱后,我用插件化把它救回来了
前端·vue.js
Hyyy2 小时前
Computer Use 适合做什么,不适合做什么——一次真实使用后的思考
前端
小和尚同志2 小时前
前端 AI 单元测试思考与落地
前端·人工智能·aigc
invicinble3 小时前
c端系统,其实更像一个信息展示平台
前端
李姆斯4 小时前
管理是否可以被完全量化
前端·产品经理·团队管理
名字还没想好☜5 小时前
Next.js 中间件实战:鉴权、重定向与 A/B 分流
开发语言·前端·javascript·中间件·react·next.js
广州灵眸科技有限公司5 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) INI文件操作
java·前端·javascript·网络·人工智能
江华森6 小时前
Web 开发基础:HTTP 与 REST
前端·网络协议·http
IT_陈寒6 小时前
Redis的KEYS命令把我搞崩溃了,改用SCAN才活过来
前端·人工智能·后端