vue实现生成pdf文件

主要就3个方法 exportReport outPutPdfFn isSplit

前置操作,我在vue原型上挂载了getPdf方法,方便复用

// 导出页面为PDF格式
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
Vue.prototype.getPdf = function (title, dom, emptyDomId) {
            // 注册getPdf方法,传入两个参数,此处使用了promise处理导出后的操作
            /*
            title: 导出文件名
            dom: 需要导出dom的id
             */
            return new Promise((resolve, reject) => {
                html2Canvas(dom, {
                    useCORS: true, // 由于打印时,会访问dom上的一些图片等资源,解决跨域问题!!重要
                    allowTaint: true // 允许跨域
                }).then(canvas => {
                    const contentWidth = canvas.width
                    const contentHeight = canvas.height
                    // 根据A4纸的大小,计算出dom相应比例的尺寸
                    const pageHeight = contentWidth / 592.28 * 841.89
                    let leftHeight = contentHeight
                    let position = 0
                    const imgWidth = 595.28
                    // 根据a4比例计算出需要分割的实际dom位置
                    const imgHeight = 592.28 / contentWidth * contentHeight
                    // canvas绘图生成image数据,1.0是质量参数
                    const pageData = canvas.toDataURL('image/jpeg', 1.0)
                    // a4大小
                    const PDF = new JsPDF('', 'pt', 'a4')
                    // 当内容达到a4纸的高度时,分割,将一整块画幅分割出一页页的a4大小,导出pdf
                    if (leftHeight < pageHeight) {
                        PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight)
                    } else {
                        while (leftHeight > 0) {
                            PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
                            leftHeight -= pageHeight
                            position -= 841.89
                            if (leftHeight > 0) {
                                PDF.addPage()
                            }
                        }
                    }
                    // 导出
                    PDF.save(title + '.pdf')
                    // 删除添加的空div

                    const emptyDom = document.getElementById(emptyDomId)
                    emptyDom.remove()
                    resolve(true)
                })
                    .catch(() => {
                        reject(false)
                    })
            })
        }

1 首先template部分就是,给你要到处pdf内容的部分加上一个id标识,用于获取这个盒子的dom对象,如图我这里的id是pdfDom

vue实现生成pdf文件_第1张图片

2 接着就是第一个方法exportReport,也就是按钮触发的方法,这个方法里面很简单,就获取了pdfDom这个盒子的dom对象,然后调用生成pdf的方法outPutPdfFn

exportReport() {
       const target = document.getElementById('pdfDom')
       this.outPutPdfFn('pdf文件名', target, 'item')
},

3 下面就是主要生成pdf文件的函数

        outPutPdfFn(title, target, itemClass) {
            const vm = this
            const A4_WIDTH = 592.28
            const A4_HEIGHT = 841.89

            vm.$nextTick(() => {
                // dom的id。

                const pageHeight = target.scrollWidth / A4_WIDTH * A4_HEIGHT
                // 获取分割dom,此处为class类名为item的dom
                const lableListID = document.getElementsByClassName(itemClass)
                // 进行分割操作,当dom内容已超出a4的高度,则将该dom前插入一个空dom,把他挤下去,分割
                for (let i = 0; i < lableListID.length; i++) {
                    const multiple = Math.ceil((lableListID[i].offsetTop + lableListID[i].offsetHeight) / pageHeight)
                    if (this.isSplit(lableListID, i, multiple * pageHeight)) {
                        const divParent = lableListID[i].parentNode // 获取该div的父节点
                        const newNode = document.createElement('div')
                        newNode.className = 'emptyDiv'
                        newNode.id = 'emptyDiv'
                        newNode.style.background = '#ffffff'
                        const _H = multiple * pageHeight - (lableListID[i].offsetTop + lableListID[i].offsetHeight)
                        newNode.style.height = _H + 30 + 'px'
                        newNode.style.width = '100%'
                        const next = lableListID[i].nextSibling // 获取div的下一个兄弟节点
                        // 判断兄弟节点是否存在
                        console.log(next)
                        if (next) {
                            // 存在则将新节点插入到div的下一个兄弟节点之前,即div之后
                            divParent.insertBefore(newNode, next)
                        } else {
                            // 不存在则直接添加到最后,appendChild默认添加到divParent的最后
                            divParent.appendChild(newNode)
                        }
                    }
                }
                // 传入title和dom标签,此处是 #content
                // 异步函数,导出成功后处理交互
                this.getPdf(title, target, 'emptyDiv').then(() => {
                    // 自定义等待动画关闭
                    this.$message({
                        type: 'success',
                        message: '导出成功'
                    })
                    this.detailSHow = false
                })
                this.$nextTick(() => {
                    const emptyDom = document.getElementById('emptyDiv')
                    emptyDom.remove()
                })


            })
        },

4 生成pdf函数中还涉及到了一个是否切割的函数判断,如下

 isSplit(nodes, index, pageHeight) {
            // 计算当前这块dom是否跨越了a4大小,以此分割
            if (nodes[index].offsetTop + nodes[index].offsetHeight < pageHeight && nodes[index + 1] && nodes[index + 1].offsetTop + nodes[index + 1].offsetHeight > pageHeight) {
                return true
            }
            return false
        },

至此一个简单的生成pdf功能就实现了,上述的方法基本都封装好了,使用上述的3个方法,只需要自己对需要生成pdf内容的盒子进行id的添加,将方法带入就可以了。

你可能感兴趣的:(vue,vue.js,pdf,javascript)