前端将表格页面导出为 PDF 并适配 A4纸张的思路

文章目录


最终效果

这个是原页面

这个是前端处理成 pdf 的效果


技术依赖包

vue2 + element + html2canvas + jsPDF

html2Canvas 官网
jsPDF 官网


优缺点

  • 优点:就是不需要后端处理 pdf 了,原本想着把 domcss 传递给后端让后端生成,奈何后端是 php,解析器不给力(这是后端跟我讲的,有没有懂 php 大佬)
  • 缺点:生成的 pdf 比较糊,而且表格在分页的时候容易分裂,我暂时没有更好的方案

实现思路

  • html 先转换成 canvas ,然后生成图片,最后再将图片转换成 pdf
  • 需要先把页面适配一下 A4 纸张大小,不然下面切割的话会出问题

代码

javascript 复制代码
import html2canvas from 'html2canvas'
import { jsPDF } from 'jspdf'

async handleUploadHTMLPDF() {
  try {
        this.loading.print = true
        const dom: any = document.querySelector('#printContent')
        const query = this.$route.query
        const id = query?.id
        if (dom) {
            html2canvas(dom).then(async canvas => {
                let pdf = new jsPDF('p', 'mm', 'a4') // A4纸,纵向
                let ctx: any = canvas.getContext('2d')
                let a4w = 190
                let a4h = 277 // A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
                let imgHeight = Math.floor((a4h * canvas.width) / a4w) // 按A4显示比例换算一页图像的像素高度
                let renderedHeight = 0
                while (renderedHeight < canvas.height) {
                    let page: any = document.createElement('canvas')
                    page.width = canvas.width
                    page.height = Math.min(imgHeight, canvas.height - renderedHeight) // 可能内容不足一页
                    // 用getImageData剪裁指定区域,并画到前面创建的canvas对象中
                    page.getContext('2d').putImageData(
                        ctx.getImageData(
                            0,
                            renderedHeight,
                            canvas.width,
                            Math.min(imgHeight, canvas.height - renderedHeight)
                        ),
                        0,
                        0
                    )
                    pdf.addImage(
                        page.toDataURL('image/jpeg', 1.0),
                        'JPEG',
                        10,
                        10,
                        a4w,
                        Math.min(a4h, (a4w * page.height) / page.width)
                    ) // 添加图像到页面,保留10mm边距

                    renderedHeight += imgHeight
                    if (renderedHeight < canvas.height) {
                        pdf.addPage() // 如果后面还有内容,添加一个空页
                    }
                    // delete page;
                }
                // 保存文件
                pdf.save('output.pdf')
                const blob = pdf.output('blob')
                const base64 = await this.blobToBase64(blob)
                // 之后想传给后端 blob 或者 base64 随便你
            })
        }
    } catch (err) {
        console.log(err)
    }
}
blobToBase64 = (blob: Blob): Promise<string> => {
    return new Promise(resolve => {
        const reader = new FileReader()
        reader.onloadend = () => resolve(reader.result as string)
        reader.readAsDataURL(blob)
    })
}

相关推荐
一斤代码1 小时前
vue3 下载图片(标签内容可转图)
前端·javascript·vue
中微子1 小时前
React Router 源码深度剖析解决面试中的深层次问题
前端·react.js
光影少年1 小时前
从前端转go开发的学习路线
前端·学习·golang
中微子2 小时前
React Router 面试指南:从基础到实战
前端·react.js·前端框架
3Katrina2 小时前
深入理解 useLayoutEffect:解决 UI "闪烁"问题的利器
前端·javascript·面试
前端_学习之路3 小时前
React--Fiber 架构
前端·react.js·架构
伍哥的传说3 小时前
React 实现五子棋人机对战小游戏
前端·javascript·react.js·前端框架·node.js·ecmascript·js
qq_424409193 小时前
uniapp的app项目,某个页面长时间无操作,返回首页
前端·vue.js·uni-app
我在北京coding3 小时前
element el-table渲染二维对象数组
前端·javascript·vue.js
布兰妮甜3 小时前
Vue+ElementUI聊天室开发指南
前端·javascript·vue.js·elementui