视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
js实现html转成pdf
2020-11-27 15:28:01 责编:小采
文档


在项目开发的时候,我们偶尔或者是经常会遇到一些难题,关于用js吧html页面转换成pdf也是一个难题,意思是说相当于把整个页面截下来,然后保存成pdf。

其实,能够实现html转pdf的方法还是挺多的,大概有以下几种:

1、大部分浏览器就有这个功能。然而我们客户要的可不是这个,人家要的是能够在系统中主动触发的导出为pdf功能,所以这种方案pass。

2、利用第三方工具。我找到了一种利用wkhtmltopdf这种工具来导出的方案,自己在我们的项目中试了一下,效果不好,而且对svg图片的支持也不行。pass。

3、还有一种是利用iText类后台生成java文件。但因为需要导出的这个页面是动态页面,而且直接把页面传给后台会丢失大量样式,所以还是pass。

最后没什么好的办法,只能退而求其次,想着要不先把html页面转成图片,再把图片导出为pdf。因为要支持用户导出下载,而且要保留样式,所以最好是纯js前端实现。

html转canvas的话,就用html2canvas这个js,这个网上介绍比较多了,这里就不废话了。

比较麻烦的是svg图片,直接用html2canvas无法把svg标签的内容转成canvas,最后查了一圈资料后,锁定了canvg这个js。canvg是谷歌的一个插件,可以将svg标签内容转成canvas。具体到我们的项目,还有一个难点,就是如何把glyphicons这种字体图标也转成canvas,因为在不同浏览器下对这种字体图标的支持是完全不一样的。最后找到的方法是用char code来替换这些字体图标,重新绘制成canvas。由canvas生成图片不用废话。由图片生成pdf用jsPDF实现。 折腾了大半天,总算把整个流程打通了,接下来一步一步贴上代码。

第一步:把对应dom节点里所有的svg元素替换成canvas

svg2canvas: function(targetElem) {
 var svgElem = targetElem.find('svg');
 svgElem.each(function(index, node) {
 var parentNode = node.parentNode;
 //由于现在的IE不支持直接对svg标签node取内容,所以需要在当前标签外面套一层div,通过外层div的innerHTML属性来获取
 var tempNode = document.createElement('div');
 tempNode.appendChild(node);
 var svg = tempNode.innerHTML;
 var canvas = document.createElement('canvas');
 //转换
 canvg(canvas, svg);
 parentNode.appendChild(canvas);
 });
}

第二步:把glyphicons字体转成canvas。如果项目中没有用到glyphicons字体图标,可忽略这一步

glyphicons2canvas: function(targetElem, fontClassName, fontFamilyName) {
 var iconElems = targetElem.find('.' + fontClassName);
 iconElems.each(function(index, inconNode) {
 var fontSize = $(inconNode).css("font-size");
 var iconColor = $(inconNode).css("color");
 var styleContent = $(inconNode).attr('style');
 //去掉"px"
 fontSize = fontSize.replace("px", "");
 var charCode = getCharCodeByGlyphiconsName(iconName);
 var myCanvas = document.createElement('canvas');
 //把canva宽高各增加2是为了显示图标完整
 myCanvas.width = parseInt(fontSize) + 2;
 myCanvas.height = parseInt(fontSize) + 2;
 myCanvas.style = styleContent;
 var ctx = myCanvas.getContext('2d');
 //设置绘图内容的颜色
 ctx.fillStyle = iconColor;
 //设置绘图的字体大小以及font-family的名字
 ctx.font = fontSize + 'px ' + fontFamilyName;
 ctx.fillText(String.fromCharCode(charCode), 1, parseInt(fontSize) + 1);
 $(inconNode).replaceWith(myCanvas);
 });
}
//根据glyphicons/glyphicon图标的类名获取到对应的char code
getCharCodeByGlyphiconsName: function(iconName) {
 switch (iconName) {
 case("glyphicons-resize-full"):
 return "0xE216";
 case ("glyphicons-chevron-left"):
 return "0xE225";
 default:
 return "";
 }
 }

第三步:html转canvas转图片再转pdf。

html2canvas($("#myExportArea"), {
 onrendered: function(canvas) {
 var imgData = canvas.toDataURL('image/jpeg');
 var img = new Image();
 img.src = imgData;
 //根据图片的尺寸设置pdf的规格,要在图片加载成功时执行,之所以要*0.225是因为比例问题
 img.onload = function() {
 //此处需要注意,pdf横置和竖置两个属性,需要根据宽高的比例来调整,不然会出现显示不完全的问题
 if (this.width > this.height) {
 var doc = new jsPDF('l', 'mm', [this.width * 0.225, this.height * 0.225]);
 } else {
 var doc = new jsPDF('p', 'mm', [this.width * 0.225, this.height * 0.225]);
 }
 doc.addImage(imgData, 'jpeg', 0, 0, this.width * 0.225, this.height * 0.225);
 //根据下载保存成不同的文件名
 doc.save('report_pdf_' + new Date().getTime() + '.pdf');
 }
 },
 background: "#fff",
 //这里给生成的图片默认背景,不然的话,如果你的html根节点没设置背景的话,会用黑色填充。
 allowTaint: true //避免一些不识别的图片干扰,默认为false,遇到不识别的图片干扰则会停止处理html2canvas
});

虽然这种方法可以将html页面转换成pdf样式,但是生成的pdf效果明显不如正常截图来的清晰,如果大家有更好的办法,欢迎指点。

下载本文
显示全文
专题