前端页⾯直接转换为PDF⽂件流⼀、代码实例
// 导出页⾯为PDF格式
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
import $jQuery from 'jquery'
import Axios from '@/axios'
import { getServerPath } from '@/constants/CommCreditClientApi'
export default {
install(Vue, options) {
Vue.prototype.uploadDom = function (domId, data) {
this.$message.info('上传开始')
let vm = this
// 将base64转换为⽂件对象
let dataURLtoFile = function (dataurl, filename) {
let arr = dataurl.split(',')
let mime = arr[0].match(/:(.*?);/)[1]
let bstr = atob(arr[1])
let n = bstr.length
let u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
/
/ 转换成file对象
return new File([u8arr], filename, { type: mime })
// 转换成成blob对象
// return new Blob([u8arr],{type:mime})
}
// pdf⽂件上传
let uploadPdf = function (file) {
// let url =''
getServerPath().then(url => {
let requestUrl = '' + url + '/oms/credit/file/param/common/paramImageManager'
console.log(requestUrl)
let formData = new FormData()
let fileList = []
fileList.push(file)
formData.append('fileList', file)
// 组装⼊参--start
pdf转htmlformData.append('batchClass', 'htmlToPdf')
formData.append('userName', Item('userName'))
formData.append('branch', JSON.Item('userInfo')).String())
formData.append('company', JSON.Item('userInfo'))String())
formData.append('operateFlag', 'A')
console.log(data)
formData.append('attachId', data.businessSeqNo)
formData.append('clientNo', data.clientNo)
formData.append('channel', data.channel)
formData.append('registerBranch', JSON.Item('userInfo')).String())
formData.append('registerUserId', Item('userName'))
formData.append('lastChangeBranch', JSON.Item('userInfo')).String())          formData.append('lastChangeUserId', Item('userName'))
// 组装⼊参--end
Axios({
method: 'post',
url: requestUrl,
data: formData
}).then(res => {
vm.$message.info('上传完成')
}).catch(() => {
vm.$('上传失败')
})
})
}
let pdfName = 'test.pdf'
let element = $jQuery(`#${domId}`)
var w = element.width() // 获得该容器的宽
var h = element.height() // 获得该容器的⾼
// var offsetTop = element.offset().top // 获得该容器到⽂档顶部的距离
// var offsetLeft = element.offset().left // 获得该容器到⽂档最左的距离
var canvas = ateElement('canvas')
canvas.width = w
canvas.height = h
var context = Context('2d')
var scale = 1
context.scale(1, 1)
// anslate(-offsetLeft, -offsetTop)
var opts = {
scale: scale,
canvas: canvas,
width: w,
height: h,
useCORS: true,
background: '#FFF',
allowTaint: false
}
html2Canvas(element[0], opts).then(function (canvas) {
let pdf = new JsPDF('p', 'mm', 'a4') // A4纸,纵向
let ctx = Context('2d')
let a4w = 190
let a4h = 277 // A4⼤⼩,210mm x 297mm,四边各保留10mm的边距,显⽰区域190x277
let imgHeight = Math.floor(a4h * canvas.width / a4w) // 按A4显⽰⽐例换算⼀页图像的像素⾼度
let renderedHeight = 0
while (renderedHeight < canvas.height) {
let page = ateElement('canvas')
page.width = canvas.width
page.height = Math.min(imgHeight, canvas.height - renderedHeight) // 可能内容不⾜⼀页
// ⽤getImageData剪裁指定区域,并画到前⾯创建的canvas对象中
pdf.DataURL('image/jpeg', 1.0), 'JPEG', 10, 10, a4w, Math.min(a4h, a4w * page.height / page.width)) // 添加图像到页⾯,保留10mm边距
renderedHeight += imgHeight
if (renderedHeight < canvas.height) {
pdf.addPage() // 如果后⾯还有内容,添加⼀个空页
}
}
// pdf.save(pdfName)
// 将pdf输⼊为base格式的字符串
let buffer = pdf.output('datauristring')
// 将base64格式的字符串转换为file⽂件
let myfile = dataURLtoFile(buffer, pdfName)
uploadPdf(myfile)
console.log(myfile)
})
}
}
}
formData⾥存放的是要传给后端的数据。后端接收到的⽂件流(即formData.fileList)是MultipartFile数组形式;这⾥需要注意⼀点,如果是单⽂件,可以直接将file放⼊fileList传输,后端依然可以像单批次多⽂件⼀样进⾏处理。除⽂件流数组外的参数,通过HttpServletRequest类型的⼊参进⾏接收,通过Parameter(key)函数获取值。
⼆、实现原理
⽤到了html2Canvas和JsPDF这两个插件。⾸先通过html2Canvas将页⾯转化为canvas元素,并进⾏裁切,然后再转化为⽂件流。
三、参考链接
以上代码综合了以下三篇⽂章。