原文地址

1.首先在文件内引入htmlToPdf.js
这里代码引入了html2canvas和jspdf
//需要 npm i html2Canvas 和 npm i jspdf

在这里将getPdf 这个函数挂载到Vue的原型上,最后return一个promise对象(包含了resolve的base64Pdf,以便于处理),在局部组件内可进行.then以进行上传后端等操作。

插件代码如下

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)
}
)
})
}
}
}

接下在main.js直接引入刚刚的代码文件

import htmlToPdf from '@/utils/htmlToPdf'

在局部组件时,准备下载时

<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);
});
},

下两个函数是上传文件的接口和base64转文件流的函数

由于是pdf的base64位至少需要1M,传给后端有些大,所以前端转成文件流formData形式传给后端

//上传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 });
},

需要注意的是 上传文件的请求头为 ‘Content-Type’: ‘multipart/form-data’,post请求。

下面代码网络请求接口文件部分代码 为个人记录,不适用于所有人项目,且为部分代码。
通常做pdf下载有上面代码就足够了,下面可忽略

//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

以上便是利用JsPDF和html2canvas先获取屏幕快照,生成pdf并以文件流形式上传到后端,默认生成的pdf为A4纸大小。

前端vue的JsPDF html2canvas 生成pdf并以文件流形式上传到后端(转载)的更多相关文章

  1. 使用 Itext 生成PDF字节数组(文件流不落地)

    package com.ulic.gis.customerCenter.controller; import java.io.ByteArrayOutputStream; import java.io ...

  2. 基于VUE利用pdf.js实现文件流形式的pdf显示

    首先推荐大家看一下这个demo vue-pdf.js-demo,这里面包含固定本地地址,远程pdf地址,通过打开文件的方式打开pdf 这儿我们着重介绍一下通过文件流的形式打开pdf.(所谓文件流,就是 ...

  3. 使用html2canvas.js实现页面截图并显示或上传

    最近写项目有用到html2canvas.js,可以实现页面的截图功能,但遭遇了许多的坑,特此写一篇随笔记录一下. 在使用html2canvas时可能会遇到诸如只能截取可视化界面.截图没有背景色.svg ...

  4. 关于vue+element对ie9的兼容el-upload不支持在IE9上传

    关于vue+element对ie9的兼容el-upload不支持在IE9上传 https://lian-yue.github.io/vue-upload-component/#/zh-cn/ 解决方案 ...

  5. netcore3.1 + vue (前后端分离) ElementUI多文件带参数上传

    vue前端代码 前端主要使用了ElementUI的el-uploda插件,除去业务代码需要注意的是使用formdata存储片上传时所需的参数 <el-upload class="upl ...

  6. 大文件分片上传,后端拼接保存(前端:antd;后端:.Net 5 WebAPI)

    前言 对于普通业务场景而言,直接用 FormData() 将文件以入参的一个参数传给后端即可,但此方法有一个弊端就是,有个 30M 的上限. 对于动辄几百 M.几个 G 的文件上传需求,FormDat ...

  7. 【应用】:shell crontab定时生成oracle表的数据到txt文件,并上传到ftp

    一.本人环境描述      1.oracle服务端装在win7 32位上,oracle版本为10.2.0.1.0      2.Linux为centos6.5 32位,安装在Oracle VM Vir ...

  8. 框架基础:ajax设计方案(三)--- 集成ajax上传技术 大文件/超大文件前端切割上传,后端进行重组

    马上要过年了,哎,回家的心情也特别的激烈.有钱没钱,回家过年,家永远是舔舐伤口最好的地方.新的一年继续加油努力. 上次做了前端的ajax的上传文件技术,支持单文件,多文件上传,并对文件的格式和大小进行 ...

  9. 前端通信:ajax设计方案(四)--- 集成ajax上传技术 大文件/超大文件前端切割上传,后端进行重组

    马上要过年了,哎,回家的心情也特别的激烈.有钱没钱,回家过年,家永远是舔舐伤口最好的地方.新的一年继续加油努力. 上次做了前端的ajax的上传文件技术,支持单文件,多文件上传,并对文件的格式和大小进行 ...

  10. 【POI】java服务生成List数据集合,后台服务生成xlsx临时文件,并将临时文件上传到腾讯云上

    场景: java服务生成List数据集合,后台服务生成xlsx临时文件,并将临时文件上传到腾讯云上 今日份代码: 1.先是一个变量,作为文件名 private static final String ...

随机推荐

  1. 【补题】The 2022 SDUT Summer Trials

    比赛链接 The 2022 SDUT Summer Trials A. Ginger's number 样例恶臭(恼) 签到题 简单分解因数就会发现要求的就是\(gcd\),直接算即可,时间复杂度\( ...

  2. 新手必学matplotlib

    Getting started Installation quick-start Install using pip: pip install matplotlib Install using con ...

  3. Git安装,配置、基本使用

    p.p1 { margin: 0; font: 12px ".PingFang SC" } p.p2 { margin: 0; text-align: justify; font: ...

  4. Appium常见属性和命令

    from appium import webdriverimport time, tracebackdesired_caps = {}desired_caps['platformName'] = 'A ...

  5. 信创要求下,FTP要不要替代?要怎么进行国产化替代?

    信创在国内如火如荼地发展,无论在技术探索和突破上,还是在政策规划上,都朝着更加完善的方向大步迈进.信创目前在从大的方面来说,信创目前主要集中在基础软件.硬件和芯片上,其中基础软件包括操作系统.数据库. ...

  6. python GIL解释器

    1.GIL是什么? GIL全称Global Interpreter Lock,即全局解释器锁. 作用就是,限制多线程同时执行,保证同一时间内只有一个线程在执行. GIL并不是Python的特性,它是在 ...

  7. JAVA线段树模板

    public class LineTree{ int[] tree,nums; int n; public LineTree(int[] nums){ this.nums = nums; n = nu ...

  8. 【Frida】启动手机上的Frida插件

    运行以下命令可以保证Frida一直在手机上运行,不关机,Frida就不关 adb shell su -c "./data/local/frida-server-15.2.2-android- ...

  9. linux 中EOF用法

    EOF是END Of File的缩写,表示自定义终止符.既然自定义,那么EOF就不是固定的,可以随意设置别名,在linux按ctrl-d就代表EOF.EOF一般会配合cat能够多行文本输出.其用法如下 ...

  10. 解决iview拖动头部横向滚动问题

    Vue.directive('dragsroll', { bind (my_el) { let elHeader = my_el.querySelector('div.ivu-table-header ...