随笔

Web 构造 PDF

之前没做过 PDF 相关的,还以为 PDF 只能顺排,HTML 页面没法控制分页,今天查了下才发现有专门针对 PDF 的样式设置,然后简单了解了下情况,对于一些特殊场景需要自动分页的需要特殊处理的情况下了个小插件处理。

媒体查询

/* 媒体查询 */
@media print {
    .wrapper {
        -webkit-print-color-adjust: exact;
        print-color-adjust:exact;
    }
}

/* 换页 */
page-break-after: always;

/* 制定打印大小, */
@page {
    size: 210mm 297mm; /* A4 纸 */
}

截断

PDF 和网页不同的就是 PDF 是一页页的,而网页是一个文档流,所以需要在合适的地方去做分页。通过 break-after 可以手动控制开启新的一页,但是当遇到不定数据时,比如列表和表格,这时候就需要有个机制去检测元素是否超出当前页面内容区域,如果超出,就要在恰当的地方去分页并自动去增加新的页。

检测是否超出用到两种手段,当然不管哪一种都要求先把原本的元素全部结构化,第一种是检测 scrollHeight 是否大于 clientHeight ,比如添加一个元素检测一次,当检测到超出时,就把最后添加的元素移除掉,然后新开一个页。

%E6%88%AA%E5%B1%8F2024-03-18_16.55.13.png

%E6%88%AA%E5%B1%8F2024-03-18_16.55.25.png

第二种是计算元素的高度,累加起来小于内容区域时,可以插入内容区域中,但是这种方式有一个弊端,就是 margin 重合的问题,目前还是推荐使用第一种方式来进行检测。

%E6%88%AA%E5%B1%8F2024-03-18_17.32.35.png

这样应对列表就足够了,表格相对就稍微复杂一点,尤其是跨行表格,以为要把表格整个结构都要读取然后数据化,一行行的去检测是否超出,还有翻到新的一个页面时,要重新把 header 再写一遍。

如果是纯文本的处理,就需要用拆分法去解决了,根据比例去计算一页能塞多少。

插件

这两天抽了点时间大概实现了下,满足了我的一些需求,复杂点的之后有需要再更新吧(里面的写法有需要的可以优化下,目前是每次新增一个元素就去单独构建一个页面去检查了,但是应该一开始就直接从真实 DOM 上操作,这样就不会每次检查 DOM 高度都去重新创建)。

目前主要是实现了列表项自动分页,无跨行列表格自动分页,或者没这些的其实也可以用,不用配置针对打印 PDF 的信息了,比如页大小,断页之类的东西,另外项目纯 JS 无依赖,所以理论上可以放在任何项目里运行。

https://github.com/lilonghe/printjs

本文链接:https://note.lilonghe.net/post/web-construct-pdf.html

-- EOF --