美文网首页
jsPDF 分页分割问题踩坑

jsPDF 分页分割问题踩坑

作者: 於風聽語 | 来源:发表于2019-12-10 11:39 被阅读0次

    jsPDF 是一个基于用于生成 PDF 文档 JS 库

    用例网上真的挺多的,一搜一大推,代码少,简洁明了,粘过来就能用,真省事。
    就是用例好像都是千篇一律的风格,互抄的吗?

    好吧,港正经话。

    网上实例导出的是 A4 大小,用到的是 addImage,以及需要 html2canvas 库。

    其实就是把需要导出的网页,利用 html2canvas 生成图片,在 addImage 至 PDF 中

    至于为什么需要先转成图片呢,直接网页转不是很好吗,还能文字复制。因为不支中文,而且,样式还原度也不高。当然,执意于文本复制,网上也有解决方式(搜索关键字:jsPDF 中文)。

    image.png QQ图片20191210103437.jpg

    分页问题

    页面过长,就涉及分页问题。

    因为 A4 是有固定页面大小的(宽:595.28, 高:841.89),保存的内容高度(缩放至A4宽度)超过该长度,则会出现截断问题。

    image.png QQ图片20191210103354.gif

    解决方法

    解决方式其实不多,分情况而定。

    1. 不分页

    其实最简单的方式是不分页。

    QQ图片20191210103601.gif

    不是吗?不分页,啥问题都没。

    这个问题就是,为什么要分页?讲真,没有分页需求,也没有打印需求,没必要分页,不是吗?整个页面导成图片就行:

    import jsPDF from 'jspdf'
    import html2canvas from 'html2canvas'
    
    function exportPDF (dom, filename) {
        const scale = 2
    
        // 滚动到顶部,避免打印不全
        document.documentElement.scrollTop = 0
    
        html2canvas(this.$refs.pdf, {
            allowTaint: true, // Whether to allow cross-origin images to taint the canvas
            scale // The scale to use for rendering. Defaults to the browsers device pixel ratio.
        }).then((canvas) => {
            const contentWidth = canvas.width / scale
            const contentHeight = canvas.height / scale
            const pdf = new jsPDF('', 'pt', [contentWidth, contentHeight])
            const pageData = canvas.toDataURL('image/jpeg', 1.0)
    
            pdf.addImage(pageData, 'JPEG', 0, 0, contentWidth, contentHeight)
            pdf.save(`${filename}.pdf`)
        })
    }
    

    2. 分页

    好吧,还是兜到分页这个坑里。

    2.1 纯静态页面

    这个比较简单,根据 A4 的尺寸比例,预留好间隔,这样,裁剪的时候,便不会出现文本或者其他内容被裁成两半。

    image.png
    2.2 动态页面

    这是最复杂的问题了吧,因为动态不好预估什么内容,什么宽高。

    - 我们需要解决的问题是什么呢?
    - 文本或者图片等被切成两半

    - 文本或者图片等,这个等又是什么呢?
    - 就是文字、图片、表格,本应该是一个整体的东西

    好吧,有点眉目了。

    页面上的内容,其实,就是一块块的块拼接在一起的,每一块,都是一个不可分割的单元,只要保证切开的地方,不是在单元格里面就行。

    示意如下图,要且在单元格(内容)间隙处(绿线),而不是单元格里面(红线)。

    image.png

    那么,我怎么知道哪些是不可分割的啊,这代码没法写啊。

    是的,代码还真不知道哪里能不能分割,除非你代码,简洁到没有嵌套,一个标签就是一个整体。

    那,人肉标记呗。

    人工标记最小单元格,给这个标签加上一个 class ,然后 js 获取这些元素,判断这些元素距离顶部的高度,以及自身的高度,来判断这个元素在那哪一页。

    const A4_WIDTH = 595.28
    const A4_HEIGHT = 841.89
    
    function splitPage ($dom) {
        const pageOffsetTop = $dom.offsetTop
        const pageOffsetWidth = $dom.offsetWidth
        const pageOffsetHeight = $dom.offsetHeight
        const $unitElements = $dom.querySelectorAll('.minimum-unit')
    
        const peerPageHeight = pageOffsetWidth / A4_WIDTH * A4_HEIGHT // 获取缩放后的一页页面高度
        const pages = [
            [
                {
                    top: 0, // 起点初始化
                    offsetTop: 0
                }
            ]
        ]
    
        // 遍历最小单元格
        // 获取单元格底部距离顶部的高度 top,以及 offsetTop
        // 根据 top 值,算出该单元格的页码,放入数组 pages
        $unitElements.forEach($element => {
            const offsetTop = $element.offsetTop - pageOffsetTop
            const top = offsetTop + $element.offsetHeight
            const pageIndex = parseInt(top / peerPageHeight)
    
            // 新的一页
            if (typeof pages[pageIndex] === 'undefined') {
              pages[pageIndex] = []
            }
    
            pages[pageIndex].push({
                top,
                offsetTop
            })
        })
    
        console.log(pages)
    
        return pages
    }
    

    导出就是(导出代码有问题,缩放比列和 pt 有问题,待解决,仅供思路参考):

    function exportPDF ($dom, filename) {
        // 滚动到页面顶部,避免导出不全
        document.documentElement.scrollTop = 0
    
        html2canvas($dom, {
            allowTaint: true,
            scale: 2
        }).then((canvas) => {
            const pdf = new jsPDF('', 'pt', 'a4')
            const contentWidth = canvas.width
            const contentHeight = canvas.height
            const pageData = canvas.toDataURL('image/jpeg', 1.0)
            const pageHeight = contentWidth / A4_WIDTH * A4_HEIGHT // 内容缩放后的高度
            const pages = splitPage()
    
            pages.forEach((page, index) => {
                const {offsetTop} = page[0]
                const {top} = page[page.length - 1]
    
                if (index > 0) {
                    pdf.addPage()
                }
    
                pdf.addImage(pageData, 'JPEG', 0, -1 * offsetTop, A4_WIDTH, top)
            })
        
            pdf.save(`${filename}.pdf`)
        })
    }
    

    分割的代码待解决,先小计一下

    QQ图片20191210103606.jpg

    —— 2019/12/10 By Vinci, Mostly Sunny.

    相关文章

      网友评论

          本文标题:jsPDF 分页分割问题踩坑

          本文链接:https://www.haomeiwen.com/subject/hmligctx.html