Vue 实现页面导出A4标准大小的PDF文件,以及处理图片跨域不能正常展示的问题等

效果预览:

代码流程:首先在utils文件夹下创建htmlToPdf的js工具文件,然后在main.js中注册引用

htmlToPdf.js

复制代码
// 导出页面为PDF格式
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'

export default {
  install(Vue, options) {
    Vue.prototype.getPdf = function (id) {
      var title = '导出试卷'
      if (id === null || id === undefined) {
        id = '#pdfDom'
      }
      html2Canvas(document.querySelector(id), {
        allowTaint: true,
      }).then(function (canvas) {
        const contentWidth = canvas.width
        const contentHeight = canvas.height
        const pageData = canvas.toDataURL('image/jpeg', 1.0)
        const pdfX = contentWidth
        const pdfY = contentHeight // 500为底部留白
        const imgX = contentWidth
        const imgY = contentHeight // 内容图片这里不需要留白的距离
        const PDF = new JsPDF('', 'pt', [pdfX, pdfY])
        PDF.addImage(pageData, 'jpeg', 0, 0, imgX, imgY)
        PDF.save(title + '.pdf')
      })
    }

    Vue.prototype.getPdfByIds = function (pages) {
      var title = '导出试卷'
      let params = []
      let PDF = null

      let imgs = document.querySelectorAll('img')
      for (let img of imgs) {
        img.setAttribute('crossorigin', '*')
      }
      let parentNode = document.querySelector(pages)
      let promises = []
      for (let i = 0; i < parentNode.childNodes.length; i++) {
        let promise = new Promise((res, rej) => {
          let pageIndex = i
          html2Canvas(
            document.querySelector('#' + parentNode.childNodes[i].id),
            {
              allowTaint: true,
              // useCORS: true,
            }
          )
            .then(function (canvas) {
              const contentWidth = canvas.width
              const contentHeight = canvas.height
              let pageData = canvas.toDataURL('image/jpeg', 1.0)
              let pdfWidth = contentWidth
              let pdfHeight = contentHeight // 500为底部留白
              let imgX = contentWidth
              let imgY = contentHeight // 内容图片这里不需要留白的距离

              params.push({
                pageIndex: pageIndex,
                pageData: pageData,
                pdfWidth: pdfWidth,
                pdfHeight: pdfHeight,
              })

              res(PDF)
            })
            .catch((e) => {
              console.log('报错', e)
            })
        })
        promises.push(promise)
      }
      Promise.all(promises).then((val) => {
        params.sort(function (a, b) {
          let index1 = a['pageIndex']
          let index2 = b['pageIndex']
          return index1 - index2 //正序
        })
        let i = 0
        for (let param of params) {
          i++
          console.log('param', param)
          let pdfWidth = param['pdfWidth']
          let pdfHeight = param['pdfHeight']
          let pageData = param['pageData']

          if (PDF === null) {
            PDF = new JsPDF('', 'pt', [pdfWidth, pdfHeight])
          } else {
            PDF.addPage()
          }
          PDF.addImage(pageData, 'jpeg', 0, 0, pdfWidth, pdfHeight)
        }
        if (params.length == parentNode.childNodes.length) {
          PDF.save(title + '.pdf')
        }
      })
    }

    Vue.prototype.getPdfByIdsB = function (pages) {
      var title = '导出试卷'
      let params = []
      let PDF = null

      let imgs = document.querySelectorAll('img')
      for (let img of imgs) {
        img.setAttribute('crossorigin', '*')
      }
      let parentNode = document.querySelector(pages)
      let promises = []
      for (let i = 0; i < parentNode.childNodes.length; i++) {
        let promise = new Promise((res, rej) => {
          let pageIndex = i
          html2Canvas(
            document.querySelector('#' + parentNode.childNodes[i].id),
            {
              allowTaint: true,
              useCORS: true,
            }
          )
            .then(function (canvas) {
              const contentWidth = canvas.width
              const contentHeight = canvas.height
              let pageData = canvas.toDataURL('image/jpeg', 1.0)
              let pdfWidth = contentWidth
              let pdfHeight = contentHeight // 500为底部留白
              let imgX = contentWidth
              let imgY = contentHeight // 内容图片这里不需要留白的距离
              params.push({
                pageIndex: pageIndex,
                pageData: pageData,
                pdfWidth: pdfWidth,
                pdfHeight: pdfHeight,
              })

              res(PDF)
            })
            .catch((e) => {
              console.log('报错', e)
            })
        })
        promises.push(promise)
      }
      Promise.all(promises).then((val) => {
        params.sort(function (a, b) {
          let index1 = a['pageIndex']
          let index2 = b['pageIndex']
          return index1 - index2 //正序
        })
        let i = 0
        for (let param of params) {
          i++
          console.log('param', param)
          let pdfWidth = param['pdfWidth']
          let pdfHeight = param['pdfHeight']
          let pageData = param['pageData']

          if (PDF === null) {
            PDF = new JsPDF('', 'pt', [pdfWidth, pdfHeight])
          } else {
            PDF.addPage()
          }
          PDF.addImage(pageData, 'jpeg', 0, 0, pdfWidth, pdfHeight)
        }
        if (params.length == parentNode.childNodes.length) {
          PDF.save(title + '.pdf')
        }
      })
    }
  },
}

在main.js中注册引用,挂载全局即可使用

复制代码
import htmlToPdf from './utils/htmlToPdf'
Vue.use(htmlToPdf)

下载方法中,使用即可,#app为最外层父级元素id名称

复制代码
//下载
      downloadPapaers() {
        Vue.prototype.getPdfByIdsB('#app')
      },
相关推荐
程序员大阳1 小时前
HTML+CSS+JS对话式实战(3)-活动管理页实现查询、新增、删除API后端接口
javascript·css·html·实战·删除·查询·新增
炫酷的大高个2 小时前
6 亿播放的闪身步,我用前端算出 15 倍重心差
前端·javascript
林小帅2 小时前
【笔记】Prisma v7 + SQLite TS2305 及连锁 TS7006 问题
前端·javascript·后端
ruanno_top2 小时前
四个 canvas 组件,在 2 倍屏上一直是糊的
vue.js
Dumbness2 小时前
订阅消息弹窗必须在用户点击里调:联调实验室里 timing 和 Mock 支付通知踩的坑
javascript·uni-app
ruanno_top3 小时前
一个脏数据能让整条折线消失:图表组件的四种数据契约
vue.js
黄连木笛3 小时前
不改一行 Postman 源码,把它汉化了:Electron preload 注入 + fetch 拦截实战
javascript·electron
叼烟扛炮4 小时前
[LangChain] 学习笔记(03):打破失忆症——对话机制与上下文管理
java·前端·javascript·笔记·学习·langchain
卋罖7505 小时前
Razor 视图 + JavaScript + Vue/iView 组件实现的表格自定义列
javascript·vue·iview·razor视图
系统集成-鹰翔19 小时前
ERP图片改名后仍命中识别缓存:缓存键、十分钟到期与调用计数
javascript·经验分享·后端