超简单!html2canvas+jspdf纯前端生成pdf

464 阅读2分钟

做后台管理系统开发,最常见的功能之一就是生成pdf,起初我一直都是使用freeMaker生成pdf,效果非常好,但是过于的依赖后端,而且比较麻烦,像比较简单的页面,如一些表格,一些页面信息之类的,使用freeMaker真是耗时耗力,好在有html2canvas+jspdf,能帮助我们快速生成pdf,且支持用jszip压缩成压缩包!

安装

npm install --save htmlcanvas2
npm install --save jspdf

使用

我们这里是使用的Vue2.0项目,并将功能做成了v-pdf指令。

首先在main.js中使用封装好的组件,代码我是放在directive目录下的pdf.js中

// 页面生成pdf
import save2Pdf from '@/directive/pdf.js'
Vue.use(save2Pdf)

使用Vue.use()使用插件,默认会给插件的install方法传递一个vue实例 Vue.use使用方法

pdf.js完整代码

import html2Canvas from 'html2canvas';
import JsPDF from 'jspdf';
export default {
    install(Vue) {
        Vue.directive('pdf', {
            inserted: function (el, binding) {
                // el:指令绑定的元素
                // 触发事件的元素
                let button = el.querySelector('#save2pdf');
                // 要生成pdf的元素
                let target = el.querySelector('#pdf');
                // 点击按钮生成pdf
                button.addEventListener("click", function () {
                    const pdf = JsPDF('', 'pt', 'a4');
                    // target.style.background = '#FFFFFF';
                    html2Canvas(target, {
                        useCORS: true, allowTaint: true, scale: 1.5,windowWidth:1350
                    }).then(canvas => {
                        const contentWidth = canvas.width
                        const contentHeight = canvas.height

                        //一页pdf显示html页面生成的canvas高度;
                        const pageHeight = (contentWidth / 595.28) * 841.89
                        //未生成pdf的html页面高度
                        let leftHeight = contentHeight
                        //页面偏移
                        let position = 0
                        //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
                        const imgWidth = 595.28
                        const imgHeight = (592.28 / contentWidth) * contentHeight

                        const pageData = canvas.toDataURL('image/jpeg', 1.5)
                        if (leftHeight < pageHeight) {
                            pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight);
                            // 为下一条数据添加空白页
                            // pdf.addPage()
                        } else {
                            while (leftHeight > 0) {
                                pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
                                leftHeight -= pageHeight
                                position -= 841.89
                                //避免添加空白页
                                if (leftHeight > 0) {
                                    pdf.addPage()
                                }
                            }
                        }
                        //v-pdf="['xxx.pdf']"  binding.value我这里是文件的名子
                        pdf.save(binding.value);
                    })
                });
            }
        })
    }
}

页面使用,需要注意的是,触发事件元素的id,我这里写的是save2pdf,要生成pdf的元素是pdf,

scale: 1.5,windowWidth:1350这是配置html2Canvas的画布,windowWidth不设置时,默认会根据你的屏幕大小生成pdf,因为默认会将整个元素在屏幕中的展现完全打印在pdf上,不设置就会造成不同屏幕生成生成的pdf页面内容大小不一致!

1690870207064.jpg

效果:

1690870374616.jpg

进阶: pdf.save()是直接生成了pdf文件,当文件过多时,可能需要将生成的pdf文件打到一个压缩包中,pdf.output('blob')会将生成pdf文件流直接返回过来,有文件流,我们就可以利用jszip库,将文件一个个的添加到zip包中,大致代码如下,亲测完美运行!

//安装jszip 
npm i --save jszip 

//引入
import JSZip from 'jszip';

const zip = new JSZip();
//将文件添加到zip中
zip.file('xxx.pdf', pdf.output('blob'))

//生成压缩包
zip.generateAsync({ type: 'blob' }).then(function(content) {
  saveAs(content, 'pdf.zip')
})