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.28
                        var 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 = true
                                        for (var j = 0; j < canvas.width; j++) {
                                            var c = canvas.getContext('2d').getImageData(j, i, 1, 1).data
                                            console.log(c)
                                            console.log("--------------------------")
                                            if (c[0] != 0xff || c[1] != 0xff || c[2] != 0xff) {
                                                isWrite = false
                                                break
                                            }
                                        }
                                        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.innerHTML
            window.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>,这些样式会被带到新界面并被调用

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

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

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值