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')
      },
相关推荐
进击的野人13 分钟前
Vue 组件与原型链:VueComponent 与 Vue 的关系解析
前端·vue.js·面试
馬致远21 分钟前
Vue todoList案例 优化之本地存储
前端·javascript·vue.js
请叫我聪明鸭21 分钟前
CSS实现单行、多行文本超长显示 / 不超长隐藏、悬浮窗超长展示/不超长隐藏、悬浮窗手动控制样式
前端·javascript·css
zfj32129 分钟前
vscode是js开发的,为什么能支持golang java等各种语言开发
javascript·vscode·golang
GDAL1 小时前
Mapbox GL JS 核心表达式:`==` 相等判断完全教程
javascript·mapbox
炸土豆1 小时前
防抖节流里的this传递
前端·javascript
林希_Rachel_傻希希1 小时前
手写Promise--教学版本
前端·javascript·面试
ETA81 小时前
`console.log([1,2,3].map(parseInt))` 深入理解 JavaScript 中的高阶函数与类型机制
前端·javascript
3秒一个大1 小时前
现代前端开发框架的工程化实践:基于 Vite 与 Vue3
vue.js
Java编程爱好者1 小时前
JUnit 5 中的 @ClassTemplate 实战指南
javascript