前端生成pdf之html2canvas+jsPDF,以及解决图片不显示bug

前端如何生成pdf

开发背景: 需要给页面中相应的内容生成pdf,查找文档后发现要用到两个插件。html2canvas 以及 jsPDF

  • html2canvas 给dom结构转化为canvas,然后生成各种类型图片
  • jsPDF 把canvas 生成的图片url 转化为pdf
javascript 复制代码
// 插入图片
pdf.addImage(image, format, x, y, width, height, alias, compression, rotation)
// 保存为pdf
pdf.save("example.pdf");

参数

  1. image:表示要插入的图片资源,可以是图片文件的路径或者base64编码字符串。
  2. format:表示要插入的图片格式,包括:'JPEG', 'PNG', 'GIF', 'BMP', 'TIFF', 'RAW', 'JPEG2000'。
  3. x:图片在PDF中的x轴坐标,单位为pt(点)。
  4. y:图片在PDF中的y轴坐标,单位为pt(点)。
  5. width:图片在PDF中的宽度,单位为pt(点)。
  6. height:图片在PDF中的高度,单位为pt(点)。
  7. alias(可选):指定图片资源的别名。
  8. compression(可选):指定图片的压缩质量,取值为0-1之间的浮点数。
  9. rotation(可选):指定图片的旋转角度,取值范围为0-360之间的整数。

下面是dom转化为pdf 的基本代码

javascript 复制代码
import html2canvas from 'html2canvas';
import jsPdf from 'jspdf';
 
function printPDF () {
    const domElement = document.getElementById('your-id');
    html2canvas(domElement, {
        onclone: (document) => {
            document.getElementById('print-button').style.visibility = 'hidden';
        }
    })
    .then((canvas) => {
        const img = canvas.toDataURL('image/png');
        const pdf = new jsPdf();
        pdf.addImage(imgData, 'JPEG', 0, 0, width, height);
        pdf.save('your-filename.pdf');
})

需要特别注意一下 html2canvas onclone 方法。它是当DOM被克隆后进行渲染时的回调函数,可用于修改将要渲染的内容,而不会影响原始DOM。当你需要在生成快照前操作 DOM(例如隐藏打印按钮)时,会非常有用。

难点突破

1. 使用html2canvas转为图片遇到跨域问题

跨域图片不会生成:由于跨域的问题(比如图片在第三方存放),导致图片不会被绘制,需要多方配置;

  1. html2canvas的配置项中配置 allowTaint:trueuseCORS:true(二者不可共同使用)

  2. img标签增加 crossOrigin='anonymous'

  3. 图片服务器配置Access-Control-Allow-Origin 或使用代理

其中第三步是最重要的,不设置则前两步设置了也无效。

如果后端不能改图片服务器,咱们前端也能设置图片代理,例如nginx server配置

bash 复制代码
	location /img {
		proxy_pass 服务器真正地址;
	}

2. html2canvas转化的图片,ios设备长按可以保存,Android设备长按无法保存

  1. 原因分析:转换后使用canvas.toDataURL拿到的是base64的图片,此图片可以直接展示在网页上,但是在Android设备上长按此图片无法保存,ios设备可以长按保存;原因是Android无法长按保存base64的图片,
  2. 解决办法:可以考虑将图片先上传到服务器拿到url再展示

3. safir长按保存不了图片

使用-webkit-touch-callout:default不规范的属性,iOS 2.0及更高版本的Safari浏览器可用

4. 生成的图片中若包含二维码,微信长按图片偶现无法识别

不使用路由切换,使用window.location.href直接跳转刷新页面

5. 生成的PDF超出一页后分页问题

  1. 需要计算图片的宽高,一页展示多少

看详细代码

javascript 复制代码
printPDF(id, name){
   const domElement = document.getElementById(id);
       html2canvas(domElement, {
            allowTaint: false,
            useCORS: true,   // 用于解决图片跨域
            onclone: (document) => {
                document.getElementById('print-button').style.visibility = 'hidden';
            }
       }).then((canvas) => {
                  
           const fileName = name + (new Date()).toLocaleString() + '.pdf'
           var pdf = new jsPdf('p', 'mm', 'a4'); // A4纸,纵向
           var ctx = canvas.getContext('2d');
           var a4w = 190; var a4h = 277; // A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
           var imgHeight = Math.floor(a4h * canvas.width / a4w); // 按A4显示比例换算一页图像的像素高度
            var renderedHeight = 0;
            while (renderedHeight < canvas.height) {
               var page = document.createElement('canvas');
               page.width = canvas.width;
               page.height = Math.min(imgHeight, canvas.height - renderedHeight);// 可能内容不足一页            
              // 用getImageData剪裁指定区域,并画到前面创建的canvas对象中
               page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)), 0, 0);
               pdf.addImage(page.toDataURL('image/jpeg', 1.0), 'JPEG', 10, 10, a4w, Math.min(a4h, a4w * page.height / page.width)); // 添加图像到页面,保留10mm边距
                
               renderedHeight += imgHeight;
               if (renderedHeight < canvas.height) {
                   pdf.addPage();// 如果后面还有内容,添加一个空页
               }
               // delete page;
             }
           // 保存文件
           pdf.save(fileName);
             
       })
 }
相关推荐
拾光拾趣录5 分钟前
CSS 深入解析:提升网页样式技巧与常见问题解决方案
前端·css
莫空00006 分钟前
深入理解JavaScript属性描述符:从数据属性到存取器属性
前端·面试
guojl7 分钟前
深度剖析Kafka读写机制
前端
FogLetter7 分钟前
图片懒加载:让网页飞起来的魔法技巧 ✨
前端·javascript·css
Mxuan8 分钟前
vscode webview 插件开发(精装篇)
前端
Mxuan9 分钟前
vscode webview 插件开发(交付篇)
前端
Mxuan10 分钟前
vscode 插件与 electron 应用跳转网页进行登录的实践
前端
拾光拾趣录10 分钟前
JavaScript 加载对浏览器渲染的影响
前端·javascript·浏览器
Codebee11 分钟前
OneCode图表配置速查手册
大数据·前端·数据可视化
然我11 分钟前
React 开发通关指南:用 HTML 的思维写 JS🚀🚀
前端·react.js·html