前端vue的JsPDF html2canvas 生成pdf并以文件流形式上传到后端(转载)
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并以文件流形式上传到后端(转载)的更多相关文章
- 使用 Itext 生成PDF字节数组(文件流不落地)
package com.ulic.gis.customerCenter.controller; import java.io.ByteArrayOutputStream; import java.io ...
- 基于VUE利用pdf.js实现文件流形式的pdf显示
首先推荐大家看一下这个demo vue-pdf.js-demo,这里面包含固定本地地址,远程pdf地址,通过打开文件的方式打开pdf 这儿我们着重介绍一下通过文件流的形式打开pdf.(所谓文件流,就是 ...
- 使用html2canvas.js实现页面截图并显示或上传
最近写项目有用到html2canvas.js,可以实现页面的截图功能,但遭遇了许多的坑,特此写一篇随笔记录一下. 在使用html2canvas时可能会遇到诸如只能截取可视化界面.截图没有背景色.svg ...
- 关于vue+element对ie9的兼容el-upload不支持在IE9上传
关于vue+element对ie9的兼容el-upload不支持在IE9上传 https://lian-yue.github.io/vue-upload-component/#/zh-cn/ 解决方案 ...
- netcore3.1 + vue (前后端分离) ElementUI多文件带参数上传
vue前端代码 前端主要使用了ElementUI的el-uploda插件,除去业务代码需要注意的是使用formdata存储片上传时所需的参数 <el-upload class="upl ...
- 大文件分片上传,后端拼接保存(前端:antd;后端:.Net 5 WebAPI)
前言 对于普通业务场景而言,直接用 FormData() 将文件以入参的一个参数传给后端即可,但此方法有一个弊端就是,有个 30M 的上限. 对于动辄几百 M.几个 G 的文件上传需求,FormDat ...
- 【应用】:shell crontab定时生成oracle表的数据到txt文件,并上传到ftp
一.本人环境描述 1.oracle服务端装在win7 32位上,oracle版本为10.2.0.1.0 2.Linux为centos6.5 32位,安装在Oracle VM Vir ...
- 框架基础:ajax设计方案(三)--- 集成ajax上传技术 大文件/超大文件前端切割上传,后端进行重组
马上要过年了,哎,回家的心情也特别的激烈.有钱没钱,回家过年,家永远是舔舐伤口最好的地方.新的一年继续加油努力. 上次做了前端的ajax的上传文件技术,支持单文件,多文件上传,并对文件的格式和大小进行 ...
- 前端通信:ajax设计方案(四)--- 集成ajax上传技术 大文件/超大文件前端切割上传,后端进行重组
马上要过年了,哎,回家的心情也特别的激烈.有钱没钱,回家过年,家永远是舔舐伤口最好的地方.新的一年继续加油努力. 上次做了前端的ajax的上传文件技术,支持单文件,多文件上传,并对文件的格式和大小进行 ...
- 【POI】java服务生成List数据集合,后台服务生成xlsx临时文件,并将临时文件上传到腾讯云上
场景: java服务生成List数据集合,后台服务生成xlsx临时文件,并将临时文件上传到腾讯云上 今日份代码: 1.先是一个变量,作为文件名 private static final String ...
随机推荐
- 【补题】The 2022 SDUT Summer Trials
比赛链接 The 2022 SDUT Summer Trials A. Ginger's number 样例恶臭(恼) 签到题 简单分解因数就会发现要求的就是\(gcd\),直接算即可,时间复杂度\( ...
- 新手必学matplotlib
Getting started Installation quick-start Install using pip: pip install matplotlib Install using con ...
- Git安装,配置、基本使用
p.p1 { margin: 0; font: 12px ".PingFang SC" } p.p2 { margin: 0; text-align: justify; font: ...
- Appium常见属性和命令
from appium import webdriverimport time, tracebackdesired_caps = {}desired_caps['platformName'] = 'A ...
- 信创要求下,FTP要不要替代?要怎么进行国产化替代?
信创在国内如火如荼地发展,无论在技术探索和突破上,还是在政策规划上,都朝着更加完善的方向大步迈进.信创目前在从大的方面来说,信创目前主要集中在基础软件.硬件和芯片上,其中基础软件包括操作系统.数据库. ...
- python GIL解释器
1.GIL是什么? GIL全称Global Interpreter Lock,即全局解释器锁. 作用就是,限制多线程同时执行,保证同一时间内只有一个线程在执行. GIL并不是Python的特性,它是在 ...
- JAVA线段树模板
public class LineTree{ int[] tree,nums; int n; public LineTree(int[] nums){ this.nums = nums; n = nu ...
- 【Frida】启动手机上的Frida插件
运行以下命令可以保证Frida一直在手机上运行,不关机,Frida就不关 adb shell su -c "./data/local/frida-server-15.2.2-android- ...
- linux 中EOF用法
EOF是END Of File的缩写,表示自定义终止符.既然自定义,那么EOF就不是固定的,可以随意设置别名,在linux按ctrl-d就代表EOF.EOF一般会配合cat能够多行文本输出.其用法如下 ...
- 解决iview拖动头部横向滚动问题
Vue.directive('dragsroll', { bind (my_el) { let elHeader = my_el.querySelector('div.ivu-table-header ...