纯js实现html转pdf的简单实例(推荐)


Posted in Javascript onFebruary 16, 2017

项目开发中遇到了一个变态需求,需要把一整个页面导出为pdf格式,而且要保留页面上的所有的表格、svg图片和样式。

简而言之,就是希望像截图一样,把整个页面截下来,然后保存成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
});

虽然最后勉强完成了客户的要求,但是生成的pdf效果明显不如正常截图来的清晰……水平所限,暂时只能想到这种方法,如果大家有更好的办法,欢迎指点。

以上这篇纯js实现html转pdf的简单实例(推荐)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript cookie解码函数(兼容ff)
Mar 17 Javascript
jQuery下通过replace字符串替换实现大小图片切换
May 22 Javascript
JavaScript节点及列表操作实例小结
Aug 05 Javascript
javascript动画系列之模拟滚动条
Dec 13 Javascript
javascript常用经典算法详解
Jan 11 Javascript
微信小程序 仿美团分类菜单 swiper分类菜单
Apr 12 Javascript
详解Vue 2.0封装axios笔记
Jun 22 Javascript
Vue.js简易安装和快速入门(第二课)
Oct 17 Javascript
小程序实现发表评论功能
Jul 06 Javascript
操作按钮悬浮固定在微信小程序底部的实现代码
Aug 02 Javascript
详解json串反转义(消除反斜杠)
Aug 12 Javascript
vue+elementUI中表格高亮或字体颜色改变操作
Nov 02 Javascript
jq给页面添加覆盖层遮罩的实例
Feb 16 #Javascript
基于JavaScript实现全选、不选和反选效果
Feb 15 #Javascript
bootstrap为水平排列的表单和内联表单设置可选的图标
Feb 15 #Javascript
bootstrap中添加额外的图标实例代码
Feb 15 #Javascript
基于JavaScript实现轮播图原理及示例
Apr 10 #Javascript
js实现模糊匹配功能
Feb 15 #Javascript
js 性能优化之算法和流程控制
Feb 15 #Javascript
You might like
PHP读取mssql json数据中文乱码的解决办法
2016/04/11 PHP
PHP 5.6.11 访问SQL Server2008R2的几种情况详解
2016/08/08 PHP
jQuery toggle()设置CSS样式
2009/11/05 Javascript
菜鸟学习JavaScript小实验之函数引用
2010/11/17 Javascript
javascript浏览器窗口之间传递数据的方法
2015/01/20 Javascript
js实现从中间开始往上下展开网页窗口的方法
2015/03/02 Javascript
jquery实现的判断倒计时是否结束代码
2016/02/05 Javascript
使用jquery提交form表单并自定义action的方法
2016/05/25 Javascript
详解angular2实现ng2-router 路由和嵌套路由
2017/03/24 Javascript
JavaScript运动框架 多物体任意值运动(三)
2017/05/17 Javascript
vue实现图书管理demo详解
2017/10/17 Javascript
浅谈React中的元素、组件、实例和节点
2018/02/27 Javascript
javascript数据结构之多叉树经典操作示例【创建、添加、遍历、移除等】
2018/08/01 Javascript
取消Bootstrap的dropdown-menu点击默认关闭事件方法
2018/08/10 Javascript
如何自定义微信小程序tabbar上边框的颜色
2019/07/09 Javascript
微信小程序 自定义弹窗实现过程(附代码)
2019/12/05 Javascript
javaScript代码飘红报错看不懂?读完这篇文章再试试
2020/08/19 Javascript
JS变量提升及函数提升实例解析
2020/09/03 Javascript
Antd下拉选择,自动匹配功能的实现
2020/10/24 Javascript
[01:02:10]DOTA2上海特级锦标赛B组小组赛#2 VG VS Fnatic第一局
2016/02/26 DOTA
[00:33]2016完美“圣”典风云人物:Sccc宣传片
2016/12/03 DOTA
Python的词法分析与语法分析
2013/05/18 Python
python遍历类中所有成员的方法
2015/03/18 Python
python自定义异常实例详解
2017/07/11 Python
django 按时间范围查询数据库实例代码
2018/02/11 Python
PyQt5每天必学之弹出消息框
2018/04/19 Python
python 执行shell命令并将结果保存的实例
2018/05/11 Python
使用Django搭建web服务器的例子(最最正确的方式)
2019/08/29 Python
CSS3制作3D立方体loading特效
2020/11/09 HTML / CSS
个人自我鉴定怎么写
2013/10/28 职场文书
2014年幼儿园元旦活动方案
2014/02/13 职场文书
环境工程专业自荐信
2014/03/03 职场文书
2014中学教师节广播稿
2014/09/10 职场文书
2014年幼儿园国庆主题活动方案
2014/09/16 职场文书
爱心捐助活动总结
2015/05/09 职场文书
大学升旗仪式主持词
2015/07/04 职场文书