记一次生成pdf的经历

8,292 阅读3分钟

继上次踩完h5的坑后,迎来了新需求,需要生成pdf,内容包括封面,目录,然后就是正文,正文的内容包括,页眉,页脚,图表,表格,图片,地图,很多地方要根据字段值的不同有不同的显示,也就是内容不固定。

最后实现的效果

封面

目录

主体内容

使用的框架

jspdf (放弃)

在网上搜到有关于jspdf的问题大致是布局比较死板,无法转换图片,分页效果差。然后就直接弃用了。(有掘友说,jspdf 这个也还行啊,结合html2canvas,也能实现一些基本的需求,目录和页眉和页脚的实现有待研究 )

tcpdf (第一版)

公司之前用的是这个插件,但是这个05年后就没有再维护了,我们第一版写的时候,虽然按需求大致上的内容的都是实现了,当然实现的过程痛苦,首先所有的布局都只能使用table布局,为什么不用padding,margin之类的呢,因为不支持啊(想哭),然后目录的问题,一开始我考虑的是前端可以通过计算每一个标题距离顶部的高度,在通过生成的pdf页面的高度去计算,标题所在的页面,but,很不准,dom计算的高度和最终pdf生成的高度差很多

wkhtmltopdf (最终版)

这个框架好啊,简单好用,基本支持前端的大部分css,除了目录有坑(只有低版本支持分页,我们现在用的是wkhtmltopdf 0.12.3版本),封面需要单独写一个页面,目录只要命令就能生成,前提是代码对应的标题要用h1标签包裹,最后生成的目录除了样式没法控制,其他都挺好的,而且点击目录的标题还能跳转到对应的标题所在的页面。下面是核心代码

//生成pdf命令
wkhtmltopdf --page-width 210mm --page-height 297mm --margin-top 15mm --header-left "这里是你的表头啦左边啦" --header-right "[date] [time]     机密文件请勿外传" --header-line --header-spacing 3 --footer-spacing 3 --footer-center "- 第 [page] 页-" cover 这里是你提前写好的封面的地址 toc --toc-header-text "目录" 这里是你要生成pdf的地址 D:\\1.pdf
// 页面的h1标签
<h1 class="item-title">
    项目信息
</h1>

需要注意的点

table跨页的时候会被分割

生成的 PDF 在分页处如下的效果

明显的发现表格的一行被切成了两部分,最后在网上找了许久的,发现解决还蛮简单的只要在不想被分割的元素上面加一条属性就好了

table{
    page-break-before: left;
}

现在就很perfect了

百度地图

我想把地图转成成图片,但是通过百度地图返回的全部都是html,而且里面的地图图片全部都是一张一张拼起来的,就算是通过html2canvas截屏也不行。最后让后端查看百度地图的文档,直接输出地图的png的链接过来。

echarts图表

因为图表是cavans,所以我们要将它转换成图片赋值给一个img标签

    let echartKLine = echarts.init(this.$el.querySelector('.js-kline'));
    echartKLine.setOption(_option);
    $("#"+this.mykey).attr("src",echartKLine.getDataURL())//通过getDataURL的方法

水印

水印找了一种简单的方法,就是给整个pdf的最外层,通过background的方法平铺。

.pdfContainer{
    background-image: url('背景图片地址');
    background-size: 300px;
}

你本地的效果的是三列水印,这也是你期望的效果,但最后出来的效果可能只有两列
所以设置的时候要根据实际生成pdf的尺寸去调整水平平铺的样式,打开开发者调试工具,将页面的宽度调整到和生成pdf后的样式差不多的宽度(也就是上面两条的情况),然后调样式,效果更佳哦,封面样式的调试也是同理。