目的:前端页面自定义元素生成pdf并提供下载

方法1:

html2canvas.min.js+jsPdf.debug.js

原理:将前端界面通过html2canvas截屏生成图片,再使用jsPdf将生成的图片存入pdf中;


//id为pdf元素容器id;
function toPdfDown(id) {var d = new Date();$("#"+id).css("overflow-x","visible")关闭页面滑动,防止生成的pdf不全var element = $("#"+id); // 这个dom元素是要导出pdf的div容器var w = element.width(); // 获得该容器的宽var h = element.height(); // 获得该容器的高var offsetTop = element.offset().top; // 获得该容器到文档顶部的距离var offsetLeft = element.offset().left; // 获得该容器到文档最左的距离var canvas = document.createElement("canvas");var abs = 0;var win_i = $(window).width(); // 获得当前可视窗口的宽度(不包含滚动条)var win_o = window.innerWidth; // 获得当前窗口的宽度(包含滚动条)if(win_o>win_i){abs = (win_o - win_i)/2; // 获得滚动条长度的一半}canvas.width = w * 2; // 将画布宽&&高放大两倍canvas.height = h * 2;var context = canvas.getContext("2d");context.scale(2, 2);context.translate(-offsetLeft-abs,-offsetTop);// 这里默认横向没有滚动条的情况,因为offset.left(),有无滚动条的时候存在差值,因此// translate的时候,要把这个差值去掉html2canvas(element).then(function(canvas) {var contentWidth = canvas.width;var contentHeight = canvas.height;//一页pdf显示html页面生成的canvas高度;var pageHeight = contentWidth / 592.28 * 841.89;//未生成pdf的html页面高度var leftHeight = contentHeight;//页面偏移var position = 0;//a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高var imgWidth = 595.28;var imgHeight = 592.28/contentWidth * contentHeight;var pageData = canvas.toDataURL('image/jpeg', 1.0);var pdf = new jsPDF('', 'pt', 'a4');//有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)//当内容未超过pdf一页显示的范围,无需分页if (leftHeight < pageHeight) {pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight);} else { // 分页while(leftHeight > 0) {pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)leftHeight -= pageHeight;position -= 841.89;//避免添加空白页if(leftHeight > 0) {pdf.addPage();}}}pdf.save('test'+d.getHours()+d.getMinutes()+d.getSeconds()+'.pdf');$("#"+id).css("overflow-x","hidden")//开启页面滑动})}

缺陷:生成pdf模糊,另外最致命的是图片会被切割,这个过程可能导致我们的元素正好被切割照成pdf的阅读问题

尝试网上改良方法:

function toPdfDown(id){if (confirm("您确认下载该PDF文件吗?")) {$("#"+id).css("overflow-x","visible")关闭页面滑动html2canvas($("#"+id), {background: "#FFFFFF",//如果指定的div没有设置背景色会默认成黑色,这里是个坑onrendered:function(canvas) {//未生成pdf的html页面高度var leftHeight = canvas.height;var a4Width = 595.28var a4Height = 841.89//一页pdf显示html页面生成的canvas高度;var a4HeightRef = Math.floor(canvas.width / a4Width * a4Height);//pdf页面偏移var position = 0;var pageData = canvas.toDataURL('image/jpeg', 1.0);var pdf = new jsPDF('x', 'pt', 'a4');var index = 1,canvas1 = document.createElement('canvas'),height;pdf.setDisplayMode('fullwidth', 'continuous', 'FullScreen');var pdfName='test';/*$('.head-content').append($('<div class="pdfTip">' +'   <div>正在生成第<span class="pdfProgress">1</span>页,共<span class="pdfTotal"></span>页...' +'</div>'));*/function createImpl(canvas) {if (leftHeight > 0) {index++;var checkCount = 0;if (leftHeight > a4HeightRef) {var i = position + a4HeightRef;for (i = position + a4HeightRef; i >= position; i--) {var isWrite = truefor (var j = 0; j < canvas.width; j++) {var c = canvas.getContext('2d').getImageData(j, i, 1, 1).dataconsole.log(c)console.log("--------------------------")if (c[0] != 0xff || c[1] != 0xff || c[2] != 0xff) {isWrite = falsebreak}}if (isWrite) {checkCount++if (checkCount >= 10) {break}} else {checkCount = 0}}height = Math.round(i - position) || Math.min(leftHeight, a4HeightRef);if(height<=0){height = a4HeightRef;}} else {height = leftHeight;}canvas1.width = canvas.width;canvas1.height = height;// console.log(index, 'height:', height, 'pos', position);var ctx = canvas1.getContext('2d');ctx.drawImage(canvas, 0, position, canvas.width, height, 0, 0, canvas.width, height);var pageHeight = Math.round(a4Width / canvas.width * height);// pdf.setPageSize(null, pageHeight)if(position != 0){pdf.addPage();}pdf.addImage(canvas1.toDataURL('image/jpeg', 1.0), 'JPEG', 0, 0, a4Width, a4Width / canvas1.width * height);leftHeight -= height;position += height;$('.pdfProgress').text(index + 1);$('.pdfTotal').text(index + Math.ceil(leftHeight / a4HeightRef));if (leftHeight > 0) {setTimeout(createImpl, 500, canvas);} else {pdf.save(pdfName + '.pdf');$('.pdfTip').remove();}}}//当内容未超过pdf一页显示的范围,无需分页if (leftHeight < a4HeightRef) {pdf.addImage(pageData, 'JPEG', 0, 0, a4Width, a4Width / canvas.width * leftHeight);pdf.save(pdfName + '.pdf')} else {try {pdf.deletePage(0);$('.pdfTip').show();$('.pdfTotal').text(index + Math.ceil(leftHeight / a4HeightRef));setTimeout(createImpl, 500, canvas);} catch (err) {console.log(err);}}}})}$("#"+id).css("overflow-x","hidden")//开启页面滑动};

该方法切割问题明显改善,但原理是计算div块高度,可以有效避免小高度块元素的切割问题,但对于太长的表格(如超一页)还是会存在切割问题,当然这个原理都清除了,哪位大佬有空完全可以去再计算一下tr的高估,但个方法资源耗费很大

直接换思路,利用浏览器自带打印功能实现pdf文件的下载

原理:通过window.print(),调用浏览器方法,具体可以去网上查询,这里列出方法打印我们想要的div

function preview (id) {//$("html").css("height", "auto");$("#"+id).after("<!--endprint-->")自己写到html里,另外注释掉这一句 打印结束标记$("#"+id).before("<!--startprint-->")//自己写到html里,另外注释掉这一句 打印起始标记let bdhtml=window.document.body.innerHTML;let sprnstr="<!--startprint-->"; //开始打印标识字符串有17个字符let eprnstr="<!--endprint-->"; //结束打印标识字符串let prnhtml=bdhtml.substr(bdhtml.indexOf(sprnstr)+17); //从开始打印标识之后的内容prnhtml=prnhtml.substring(0,prnhtml.indexOf(eprnstr)); //截取开始标识和结束标识之间的内容window.document.body.innerHTML=prnhtml; //把需要打印的指定内容赋给body.innerHTMLwindow.print(); //调用浏览器的打印功能打印指定区域window.document.body.innerHTML=bdhtml;//重新给页面内容赋值;//$("html").css("height", "100%");return false;}

该方法实现本页打印;但依旧存在问题

1:对于只打印一页,仔细查查html是否设置了height:100%;如果设置了在方法里修改html的css

2:对于页面存在js动态绑定的方法,需要刷新页面否则按键会失效

最终版: 为应对第二种问题我选择在新窗口进行打印

function doPrint() {let winname,head,bdhtml,sprnstr,eprnstr,prnhtml;//$("html").css("height", "auto");winname = window.open('', "_blank",'');head ='';//注意这里!!bdhtml=window.document.body.innerHTML;sprnstr="<!--startprintBG-->";eprnstr="<!--endprintBG-->";prnhtml=bdhtml.substr(bdhtml.indexOf(sprnstr)+19);prnhtml=prnhtml.substring(0,prnhtml.indexOf(eprnstr));winname.document.head.innerHTML=head;winname.document.body.innerHTML=prnhtml;winname.print();//$("html").css("height", "100%");
}

最终问题及解决思路:

该方法会照成打开界面时css样式的丢失,如果全写的内联那不存在这个问题,仔细检索发现是样式未传递过来(如果你的样式放在服务器上,大可在head里直接window.document.head.innerHTML);

解决:在head中写入<style> 样式.............. </style>,这些样式会被带到新界面并被调用

至于打印的一些默认样式,这个自己百度网上有

——————————————————————————————————————以上结束—————————————————————————————————————————————————

js,前端下载PDF方法总结相关推荐

  1. 纯前端下载pdf链接文件,而不是打开预览的解决方案

    纯前端下载pdf链接文件,而不是打开预览的解决方案 参考文章: (1)纯前端下载pdf链接文件,而不是打开预览的解决方案 (2)https://www.cnblogs.com/jackson-yqj/ ...

  2. 使用js直接下载pdf文件而不用在新的浏览器窗口打开

    最近接了一个需求,要求用户点击下载按钮后直接下载pdf文件,而不是打开一个新窗口,让用户再去手动保存. 接到需求后我立刻着手在网上查找文档,发现很多声称可以实现直接下载的方法都不行,只有下面这个方法成 ...

  3. js前端下载文件,利用download.js或者,纯js下载文件,图片,视频,pdf等

    目前,我在百度上,找到了三种方式,下载 第一种 这个方法,用的是FileReader然后readAsDataURL,我自己测试,会比方法二,下载速度要快一点 下面的代码段,可以替换,方法三种 down ...

  4. 前端下载pdf文档(支持doc/excel/ppt/pdf/jpg、png等)

    一.前端有后台返回的各种文档在服务器上的链接地址,实现点击下载文件 1.以a链接点击下载文件列表 <a v-for="item in tips.filemaintains" ...

  5. 前端下载文件方法、 后台接口返回二进制文件流、前端通过blob对象并使用fetch/axios实现下载

    在项目中实现文件下载的方法: 一.接口返回url或者get请求访问接口直接下载. window.location.href = xxxurl 使用a标签下载 const alink= document ...

  6. JS前端常用工具方法

    目录 1. 邮箱 2. 手机号码 3. 电话号码 4. URL地址 5. 是否字符串 6. 是否数字 7. 是否Boolean 8. 是否函数 9. 是否为null 10. 是否undefined 1 ...

  7. 下载文件、(Blob数据流)下载PDF

    下载文件.(Blob数据流)下载PDF 方法一 (a标签) downloadFile(file) {let url= '你的文件地址'const elink = document.createElem ...

  8. 前端下载图片的N种方法

    前几天一个简单的下载图片的需求折腾了我后端大佬好几天,最终还是需要前端来搞,开始说不行的笔者最后又行了,所以趁着这个机会来总结一下下载图片到底有多少种方法. 先起个服务 使用expressjs起个简单 ...

  9. 6种实现前端下载图片的方法汇总

    来源 | https://www.cnblogs.com/wanglinmantan/p/15088419.html 前几天一个简单的下载图片的需求折腾了我后端大佬好几天,最终还是需要前端来搞,开始说 ...

最新文章

  1. ADMT3.2域迁移之Server2003至Server2012系列(八)生成密钥文件及安装密码迁移工具...
  2. linux下内存测试mbw,【转帖】MBW内存测试
  3. FLV 数据封装格式
  4. java apache fileutil_Java FileUtil.listFiles方法代码示例
  5. 空间句法软件_【特训营2:空间句法高阶班】GIS中的空间句法运用 丨城市数据派...
  6. 图解MySQL 内连接、左连接、右连接
  7. Google Maps 地址转化成坐标
  8. ASP.NET操作Excel(终极方法NPOI)
  9. Selenium学习(2) 元素定位
  10. The Future of Compass ElasticSearch
  11. FCKeditor 配置、扩展
  12. Java高并发BlockingQueue重要的实现类
  13. Team Foundation Server XXX 不存在,或者此时不可访问:解决方案
  14. mt7620a上wifi中继的实现
  15. Linux实操篇-组管理和权限管理
  16. wpf实现类似word文档的标尺功能
  17. 计算内容热度的算法解释
  18. C#高级编程——C#扩展方法+接口,定义统一的搜索接口,基于Unity(三)——图文详解加源码
  19. 【JAVA百炼成仙】特别篇——(三个IO练习题)
  20. 客厅窗帘最实用的色彩组合搭配,大气稳重-窗帘十大品牌江南爱

热门文章

  1. 算法:挑选出100瓶药水中有且仅有1瓶毒药水所需的最少老鼠数量?
  2. MySQL数据库教程天花板,mysql安装到mysql高级,强|硬 宋红康版(自用不可外传)
  3. UC如被百度控股,手机qq浏览器改如何进攻和防守
  4. java 仿qq空间_仿QQ空间和微信朋友圈,高解耦高复用高灵活
  5. 王阳明心学 量子物理_量子物理学论文的文本分类
  6. 大数据在医疗领域的应用
  7. python数值运算m op n_M OP N数值运算问题
  8. Linux 内核中 likely 与 unlikely 的宏定义解析
  9. ipad已有2周未备份。ipad插入电源、被锁定且接入Wi-Fi时会进行备份
  10. 微信公众号前后端分离授权登录