jspdf + html2canvas 开发前端pdf导出功能记录

目录

插件

实现

简单分页

进一步分页

关于html2canvas的一点小经验


最近在开发项目的时候,接到了一个需求。听起来是比较简单的,将后台系统的报表以pdf文件的形式导出。excel导出,图片导出都做过了,现在轮到pdf了。在实现的过程中遇到了一些困难,通过查阅资料,网上各位朋友使用过的经验后,差不多完成。写这篇博客希望将自己的经验留下,帮助到更多的朋友。

插件

PDF类

  1. pdfmake  官网地址: https://pdfmake.github.io/docs/getting-started/

  2. jspdf  官网地址: http://raw.githack.com/MrRio/jsPDF/master/docs/index.html

DOM转化为Canva

     1. html2canvas  官网地址: http://html2canvas.hertzen.com/getting-started

 

实现

最初我是想使用pdfmake来自定义报告表单的,无奈自定义起来太麻烦,比如一些合并单元格的操作需要花费太多时间去研究,后面直接转投pdf,原因还是觉得jspdf与html2canvas直接转换图片使用起来比较快,直接把图片放入pdf即可。

先根据网址进到每个插件中,选择适当的方法将插件下载下来。接下来直接开撸代码,话不多说,贴上测试代码。

 

简单分页

下面试简单的将一个指定的表格转换为pdf,包含了最简单的分页。

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>PDF导出测试</title>
    <style>
        * {
            margin: 0;
        }

        .container {
            height: 400px;
            overflow-y: auto;
        }

        .content {
            margin-top: 20px;
        }

        table {
            border-collapse: collapse;
            font-size: 16px;
            width: 80%;
            margin: 0 auto;
            word-break: break-all;
        }

        td {
            padding: 5px;
            border: 1px solid;
            text-align: center;
        }
    </style>
</head>
<script src="./js/html2canvas.min.js"></script>
<script src="https://unpkg.com/jspdf@latest/dist/jspdf.min.js"></script>

<body>
    <div>
        <button onclick="getContent()">导出PDF</button>
    </div>
    <div class="container">
        <div class="content">
            <table>
                <tr>
                    <td>报告</td>
                    <td>结果</td>
                    <td>数值</td>
                    <td>数值</td>
                    <td>数值</td>
                    <td>数值</td>
                    <td>数值</td>
                </tr>
                <tr>
                    <td>1</td>
                    <td>2</td>
                    <td>3</td>
                    <td>3</td>
                    <td>3</td>
                    <td>3</td>
                    <td>3</td>
                </tr>
            </table>
        </div>
    </div>
</body>
<script src="../pdfmake/build/vfs_fonts.js"></script>
<script>
    // 增加测试数据
    function addTr() {
        const table = document.querySelector('table');
        const tr = document.querySelectorAll('tr')[1];
        for (let i = 1; i < 100; i++) {
            var nTr = document.createElement('tr');
            nTr.innerHTML = tr.innerHTML;
            table.appendChild(nTr);
        }
    }
    addTr();



    function getContent() {
        const content = document.querySelector('.content'); // 获取待导出的pdf内容DOM
        const rect = content.getBoundingClientRect(); // 获取pdf内容DOM的位置
        var pdf = new jsPDF('', 'pt', 'a4') // 初始化jspdf对象
        generatePDF(content, pdf, rect);

    }

    function generatePDF(content, pdf, rect) {
        console.log(rect.top);
        const op = {
            scale: 1,
            logging: true,
            width: Number(getComputedStyle(content).width.replace('px', '')), // 设置画布的宽度
            height: Number(getComputedStyle(content).height.replace('px', '')) // 设置画布的高度
        };

        html2canvas(content, op).then(
            canvas => {
                const data = canvas.toDataURL('png', 1);  // 将生成的canva转换为base64
                var imgWidth = 595.28; // 设置图片在pdf中宽度
                var imgHeight = 592.28 / canvas.width * canvas.height; //设置图片在pdf中的高度
                var singlePdfHeight = 841.89; // pdf单页的高度
                var singlePageHeight = canvas.width / 592.28 * 841.89; // A4纸单页高度在canvas中对应的高度
                var position = 0; //每一页pdf偏移量
                var leftHeight = canvas.height; // 剩余高度
                if (leftHeight < singlePageHeight) {
                    // 如果canvas图片总高度比pdf单页高度小可直接生成图片
                    pdf.addImage(data, 'PNG', 0, 0, imgWidth, imgHeight);
                } else {
                    // 如果canvas图片总高度比pdf单页高度大, 循环生成pdf
                    while (leftHeight > 0) {
                        pdf.addImage(data, 'PNG', 0, position, imgWidth, imgHeight);
                        leftHeight -= singlePageHeight;
                        position -= singlePdfHeight;
                        if (leftHeight > 0) {
                            pdf.addPage(); // 若一页高度无法显示完整个内容,增加新一页Pdf
                        }

                    }
                }

                pdf.save("content.pdf");
            }
        );
    }


</script>

</html>

进一步分页

这里我就提供一下思路:

那这个table表格做列子, 可以通过单页A4纸换算到html的高度,然后根据这个高度将html中要截取的内容进行分割。最后分割为几部分就有几页即调用几次html2canvas。 通过调整html2canvas配置中的y参数来达到分页效果。

 

关于html2canvas的一点小经验

这里要提一个关于html2canvas生成的canvas中内容偏移量的问题。 你有可能遇到使用html2canvas得到的内容与自己的预期不一致,想要明白为什么主要要搞清楚html2canvas的默认配置。

假设你要截取的html内容块的外层DOM为  warpper

const warpper = document.querySelector('.warpper');

option {

   scale: 默认值为window.devicePixelRatio--如果你不设置值可能会导致你的canvas画布比实际设置的值偏大

   y:  默认值为 wapper.getBoundingClientRect().top + window.pageYOffset 

   x:  默认值为 wapper.getBoundingClientRect().left + window.pageXOffset 

}

 

在官方文档中,我没有找到对y的默认值,翻看源码后才发现。所以我在开发过程中相同的代码,不同的样式中可能得到的效果不一样。因此根据源码中的默认值为基础来调整canvas中内容偏移位置,得到你想要的效果。

比如想要设置纵向上的偏移量,要注意window.pageYOffset是否考虑进去。


使用addImage插入不同图片只显示第一张图片问题

最近再次使用jspdf开发,使用addImage插入多张不同的图片,发现无论怎么插入pdf中所有页面都只显示第一张图片。看了源码后发现, 要在pdf中插入不同图片的话,addImage方法的入参alias要么不要设置,如果一定要设置的情况下一定要为每张图片的alias设置不同的值,我这里使用时间戳。

原因是每次addImage会根据alias这个字段去查图片缓存,如果alias已经在之前的操作中存在,就会用之前alias对应的图片。

 

希望可以帮助到各位,如果文中有问题的地方欢迎大家留言一起讨论。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值