Das JsPDF html2canvas des Front-End-Vue generiert PDF und lädt es als Dateistream in das Back-End hoch

1. Führen Sie zunächst htmlToPdf.js in die Datei ein

Dieser Code führt html2canvas und jspdf ein
//需要 npm i html2Canvas 和 npm i jspdf

Hier wird die getPdf-Funktion an den Vue-Prototyp gemountet und schließlich ein Promise-Objekt zurückgegeben (einschließlich des aufgelösten base64Pdf zur einfachen Verarbeitung). Anschließend kann es in der lokalen Komponente ausgeführt werden, um das Backend und andere Vorgänge hochzuladen.

Der Plug-in-Code lautet wie folgt

import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
export default {
    
    
  install(Vue, options) {
    
    
    /**
     * 
     * @param {*} reportName 下载时候的标题
     * @param {*} isDownload  是否下载默认为下载,传false不下载
     */
    Vue.prototype.getPdf = function (reportName, isDownload = true) {
    
    
      //     var target = document.getElementsByClassName("right-aside")[0];
      // target.style.background = "#FFFFFF";
      return new Promise((resolve, reject) => {
    
    
        var title = reportName;
        html2Canvas(document.querySelector('#pdfDom'), {
    
    
          allowTaint: true
        }).then((canvas) => {
    
    
          let contentWidth = canvas.width
          let contentHeight = canvas.height
          //一页pdf显示html页面生成的canvas高度;
          let pageHeight = contentWidth / 592.28 * 841.89
          //未生成pdf的html页面高度
          let leftHeight = contentHeight
          //页面偏移
          let position = 0
          //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
          let imgWidth = 595.28
          let imgHeight = 592.28 / contentWidth * contentHeight
          let pageData = canvas.toDataURL('image/jpeg', 1.0)
          let PDF = new JsPDF('', 'pt', 'a4')
          //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
          //当内容未超过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()
              }
            }
          }
          if (isDownload) {
    
    
            PDF.save(title + '.pdf')
          }
          // 删除本地存储的base64字段
          var pdfData = PDF.output('datauristring')//获取base64Pdf
          resolve(pdfData)
        }
        )
      })
    }
  }
}

Als nächstes importieren Sie die Codedatei direkt in main.js

import htmlToPdf from '@/utils/htmlToPdf'

In Teilkomponenten, wenn zum Download bereit

  <button @click="toGetPdf(0)">下载PDF</button>//这种情况是只下载,不上传后端
  <button @click="toGetPdf(1, 0)">下载PDF</button>//这种情况是只走上传后端接口,不下载
 toGetPdf(val = false, download = true) {
    
    
      /**
     * val 决定走不走上传接口,默认为不上传给后端
     * download 默认是下载
     * /
 
      /* */
      this.$nextTick(() => {
    
    
        setTimeout(() => {
    
    
          window.scrollTo(0, 0);     //这行代码很重要,它让页面的滚动条跳到了最上方如果点击打印按钮的时候,滚动条没有在最上方,打印内容会是不完整的,体验也会差
          let title ="个人报告"
          this.getPdf(title, download) //download:false为不下载,这里调用了刚刚引用的全局函数,.then得到的值是base64位的pdf文件
            .then((res) => {
    
    
              if (val) {
    
    
                console.log("准备上传");
                this.UploadPdf(res);
              } else {
    
    
                console.log("不上传");
              }
            });
        }, 1000);
      });
    },

Die nächsten beiden Funktionen sind die Schnittstelle zum Hochladen von Dateien und die Funktion zum Konvertieren von Base64 in Dateistreams

Da das Base64-Bit von PDF mindestens 1 MB benötigt, ist es für die Übergabe an das Backend etwas groß. Daher konvertiert das Frontend es in einen Dateistrom von FormData und übergibt ihn an das Backend

//上传pdf接口
    UploadPdf(res) {
    
    
     //res拿到base64的pdf
      let pdfBase64Str = res;
      let title ="上传给后端的个人报告"
      var myfile = this.dataURLtoFile(pdfBase64Str, title + ".pdf");//调用一下下面的转文件流函数
      var formdata = new FormData();
      formdata.append("file", myfile); // 文件对象
      //该uploadMy为接口,直接以formdata格式传给后台
      uploadMy(formdata)
        .then((res) => {
    
    
          console.log("上传pdf接口", res);
        })
        .catch((err) => {
    
    
          console.log("上传pdf接口", err);
        });
    },
    
/*
将base64转换为文件,接收2个参数,第一是base64,第二个是文件名字
最后返回文件对象
*/
   dataURLtoFile(dataurl, filename) {
    
    
      var arr = dataurl.split(","),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n);
      while (n--) {
    
    
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new File([u8arr], filename, {
    
     type: mime });
    },

Es ist zu beachten, dass der Anforderungsheader der hochgeladenen Datei „Content-Type“ lautet: „multipart/form-data“, Post-Anfrage.

Ein Teil des Codes in der Netzwerkanforderungsschnittstellendatei unten ist ein persönlicher Datensatz, der nicht auf alle Projekte anwendbar ist und Teil des Codes ist.
Normalerweise reicht es aus, den PDF-Download mit dem obigen Code durchzuführen, der unten ignoriert werden kann

//api/index.js文件:

import $request from '@/utils/http'
let baseUrl = '/api/test'


if (process.env.NODE_ENV === 'development') {
    
    
  baseUrl = '/dev'
  bigDataUrl = '/service'
  collectUrl = '/collect'
}
// 上传文件-个人
export function uploadMy(data) {
    
    
  return $request.postUpload(baseUrl + '/common/upload', data)
}


//@/utils/http.js文件
import axios from './request'
/** post请求 lcl编写 请求头为上传的请求头*/
function postUpload(url, data,config) {
    
    
  return new Promise((resolve, reject) => {
    
    
    axios.post(url, data, config?config:{
    
    
     headers: {
    
    
        // 'Content-Type': 'application/x-www-form-urlencoded'
        'Content-Type': 'multipart/form-data'
      }
    }).then((res) => {
    
    
      // if (res.data.code === '801' || res.data.code === '802' || res.data.code === '804') {
    
    
      //   removeToken()
      //   router.push({ name: 'login' })
      // }
      resolve(res.data)
    }).catch((err) => {
    
    
      reject(err)
    })
  })
}



//@/utils/request.js文件

import axios from 'axios'
// import { Message, MessageBox } from 'element-ui'
import store from '@/store'
import {
    
     getToken, removeToken} from '@/utils/auth'

// create an axios instance

const service = axios.create({
    
    
  // baseURL: process.env.VUE_APP_APIURL, 
  // baseURL: "/api/test", 
  timeout: 20000 // request timeout  超过20s则失败
})

// request interceptor
service.interceptors.request.use(
  config => {
    
    
    // Do something before request is sent
    // 让每个请求携带token-- ['Token']为自定义key 请根据实际情况自行修改
    if(store.getters.token) {
    
    
      config.headers['Authorization'] = store.getters.token
    }
    return config
  },
  error => {
    
    
    Promise.reject(error)
  }
)

// response interceptor
service.interceptors.response.use(
  // response => response,
  /**
   * 下面的注释为通过在response里,自定义code来标示请求状态
   * 当code返回如下情况则说明权限有问题,登出并返回到登录页
   * 如想通过 xmlhttprequest 来状态码标识 逻辑可写在下面error中
   * 以下代码均为样例,请结合自生需求加以修改,若不需要,则可删除
   */

  response => {
    
    
    const res = response.data
    if (res.code !== 200 && res.code !== 204) {
    
    
      // Message({
    
    
      //   message: res.msg,
      //   type: 'error',
      //   duration: 5 * 1000
      // })
      if (res.code === 401  || res.code === 501 || res.code === 804) {
    
    
        // 请自行在引入 MessageBox
        // import { Message, MessageBox } from 'element-ui'
        // MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
    
    
        //   confirmButtonText: '重新登录',
        //   cancelButtonText: '取消',
        //   type: 'warning'
        // }).then(() => {
    
    
          removeToken();
          location.reload();
          store.dispatch('FedLogOut').then(() => {
    
    
            location.reload() // 为了重新实例化vue-router对象 避免bug
          });
          
        // })
      }
      return Promise.reject(res)
    } else {
    
    
      return response
    }
  },
  error => {
    
    
    // Message({
    
    
    //   message: error.msg,
    //   type: 'error',
    //   duration: 5 * 1000
    // })
    return Promise.reject(error)
  }
)

export default service

Das Obige besteht darin, mit JsPDF und html2canvas zunächst Screenshots zu erstellen, ein PDF zu generieren und es in Form eines Dateistreams in das Backend hochzuladen. Das standardmäßig generierte PDF hat das Papierformat A4.

おすすめ

転載: blog.csdn.net/qq_38594056/article/details/118212082