近期的一个的需求,HTML 生成 PDF,整个过程让前端来实现,因为后端大神实在太忙.
网上搜索的一番,看到 有两种实现方式:
- 手动写入内容到 PDF, jsPDF支持文字图片写入然后直接生成 PDF,可以结合antoTable 更容易的展示表格
- 使用 html2pdf 这个库,其实现机理是 DOM => IMAGE => PDF
针对我们的实际情况,我们是要根据打印一个特定的页面,但是同时还会增加一些只会在 PDF 当中展示的内容,其实相当于新写了一个页面专门用于打印,打印的内容包括 chart 和 一些复杂的排版内容,给予这两点,第一种方法就被舍弃了.
第二种方法实现的过程:
- 我们使用的 react,所以我们新写了一个组件,在点击打印的时候载入,设置为不可见
- 在页面 dom 渲染结束后调用 html2pdf 库,调用类似
html2pdf().set(option).from(element).save()
下面就说一下使用后出现的问题和解决思路:
- 我们的 table 过长,column 非常多,这就需要非常宽的页面支持,最后我们使用的自定义页面宽度
- PAGE-BREAK. 虽然支持 css 的 page-break,但是碰到 table 时候,就会直接从
tr
断开,下一页让人无法对应每一列的内容.所以这里需要自己用 js 处理. 思路: 计算 table 在当前页面可以放多少行,然后就在边缘那一行增加一个tr
,把 thead 的内容放进去,并在 tr 上加上 break-before 的类,这样就可以实现table分页并且thead也能在下一页继续使用 - 分页: 这个可以在最后使用 setFont 给每一页写入页码```javascript worker.get(‘pdf’).then(pdf=>{ const totalPage = pdf.internal.getNumberOfPages(); for(let j=1;j<totalPage; j++){ pdf.setPage(j); pdf.setFontSize(20); pdf.text(
page ${j}
)
}
})
1 |
|
使用这种方案仍然有两个 issue:
- 渲染时间偏长,二十页左右的要两三分钟,这可能和 pdf 要重复执行 canvas 有关
- 但分的小块里面,其大小仍然超过 canvas size 还是会出现空白页
这个方案目前还没找到解决方案
看来,做 PDF 这个事情还得找后端去做.