js,前端下载PDF方法总结
目的:前端页面自定义元素生成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方法总结相关推荐
- 纯前端下载pdf链接文件,而不是打开预览的解决方案
纯前端下载pdf链接文件,而不是打开预览的解决方案 参考文章: (1)纯前端下载pdf链接文件,而不是打开预览的解决方案 (2)https://www.cnblogs.com/jackson-yqj/ ...
- 使用js直接下载pdf文件而不用在新的浏览器窗口打开
最近接了一个需求,要求用户点击下载按钮后直接下载pdf文件,而不是打开一个新窗口,让用户再去手动保存. 接到需求后我立刻着手在网上查找文档,发现很多声称可以实现直接下载的方法都不行,只有下面这个方法成 ...
- js前端下载文件,利用download.js或者,纯js下载文件,图片,视频,pdf等
目前,我在百度上,找到了三种方式,下载 第一种 这个方法,用的是FileReader然后readAsDataURL,我自己测试,会比方法二,下载速度要快一点 下面的代码段,可以替换,方法三种 down ...
- 前端下载pdf文档(支持doc/excel/ppt/pdf/jpg、png等)
一.前端有后台返回的各种文档在服务器上的链接地址,实现点击下载文件 1.以a链接点击下载文件列表 <a v-for="item in tips.filemaintains" ...
- 前端下载文件方法、 后台接口返回二进制文件流、前端通过blob对象并使用fetch/axios实现下载
在项目中实现文件下载的方法: 一.接口返回url或者get请求访问接口直接下载. window.location.href = xxxurl 使用a标签下载 const alink= document ...
- JS前端常用工具方法
目录 1. 邮箱 2. 手机号码 3. 电话号码 4. URL地址 5. 是否字符串 6. 是否数字 7. 是否Boolean 8. 是否函数 9. 是否为null 10. 是否undefined 1 ...
- 下载文件、(Blob数据流)下载PDF
下载文件.(Blob数据流)下载PDF 方法一 (a标签) downloadFile(file) {let url= '你的文件地址'const elink = document.createElem ...
- 前端下载图片的N种方法
前几天一个简单的下载图片的需求折腾了我后端大佬好几天,最终还是需要前端来搞,开始说不行的笔者最后又行了,所以趁着这个机会来总结一下下载图片到底有多少种方法. 先起个服务 使用expressjs起个简单 ...
- 6种实现前端下载图片的方法汇总
来源 | https://www.cnblogs.com/wanglinmantan/p/15088419.html 前几天一个简单的下载图片的需求折腾了我后端大佬好几天,最终还是需要前端来搞,开始说 ...
最新文章
- ADMT3.2域迁移之Server2003至Server2012系列(八)生成密钥文件及安装密码迁移工具...
- linux下内存测试mbw,【转帖】MBW内存测试
- FLV 数据封装格式
- java apache fileutil_Java FileUtil.listFiles方法代码示例
- 空间句法软件_【特训营2:空间句法高阶班】GIS中的空间句法运用 丨城市数据派...
- 图解MySQL 内连接、左连接、右连接
- Google Maps 地址转化成坐标
- ASP.NET操作Excel(终极方法NPOI)
- Selenium学习(2) 元素定位
- The Future of Compass ElasticSearch
- FCKeditor 配置、扩展
- Java高并发BlockingQueue重要的实现类
- Team Foundation Server XXX 不存在,或者此时不可访问:解决方案
- mt7620a上wifi中继的实现
- Linux实操篇-组管理和权限管理
- wpf实现类似word文档的标尺功能
- 计算内容热度的算法解释
- C#高级编程——C#扩展方法+接口,定义统一的搜索接口,基于Unity(三)——图文详解加源码
- 【JAVA百炼成仙】特别篇——(三个IO练习题)
- 客厅窗帘最实用的色彩组合搭配,大气稳重-窗帘十大品牌江南爱
热门文章
- 算法:挑选出100瓶药水中有且仅有1瓶毒药水所需的最少老鼠数量?
- MySQL数据库教程天花板,mysql安装到mysql高级,强|硬 宋红康版(自用不可外传)
- UC如被百度控股,手机qq浏览器改如何进攻和防守
- java 仿qq空间_仿QQ空间和微信朋友圈,高解耦高复用高灵活
- 王阳明心学 量子物理_量子物理学论文的文本分类
- 大数据在医疗领域的应用
- python数值运算m op n_M OP N数值运算问题
- Linux 内核中 likely 与 unlikely 的宏定义解析
- ipad已有2周未备份。ipad插入电源、被锁定且接入Wi-Fi时会进行备份
- 微信公众号前后端分离授权登录