1.需求
前端需要自己把当前页面或者某个盒子的内容导出成PDF文件并下载
2.工具下载
安装jspdf: npm install jspdf --save
安装html2Canvas: npm install --save html2canvas
3.封装方法
先建一个downloadHtmlToPdf.js文件,然后再main.js中全局引用即可
//main.js引用 也可以单独引用
import downloadHtmlToPdf from '@/util/downloadHtmlToPdf'
Vue.use(downloadHtmlToPdf)
downloadHtmlToPdf.js
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
export default {
install(Vue, options) {
Vue.prototype.downloadHtmlToPdf = function () {
var pdfName = this.htmlTitle
html2Canvas(document.querySelector('#printer'), {
scale: 4, // 提升画面质量,但是会增加文件大小
useCORS: true, // 允许跨域图片 当图片是链接地址时,需加该属性,否组无法显示图片
dpi: 300 // 将分辨率提高到特定的DPI
}).then((canvas) => {
// A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
const A4_WIDTH = 190
const A4_HEIGHT = 277
// 画布的尺寸
const contentWidth = canvas.width
const contentHeight = canvas.height
// 一页 pdf html 页面生成的 canvas 高度;
const pageHeight = Math.floor(contentWidth / A4_WIDTH) * A4_HEIGHT
// 未生成 pdf 的 html 页面高度
let leftHeight = contentHeight
// 页面偏移
let position = 0
const pageData = canvas.toDataURL('image/jpeg', 1.0)
// const pdf = new JsPDF('p', 'mm', 'a4') // A4纸,纵向
//此处判断是否大于一页,如果小于一页,则动态设置页面高度
let pdf;
if(contentHeight/contentWidth < A4_HEIGHT/A4_WIDTH){
let h = Math.max(210/contentWidth*contentHeight, 210);//最低210
pdf = new JsPDF('p', 'mm', [210, h])
}else{
pdf = new JsPDF('p', 'mm', 'a4') // A4纸,纵向
}
// index = 1,
let canvas1 = document.createElement('canvas'),
height
pdf.setDisplayMode('fullwidth', 'continuous', 'FullScreen')
function createImpl(canvas) {
if (leftHeight > 0) {
// index++
var checkCount = 0
if (leftHeight > pageHeight) {
var i = position + pageHeight
for (i = position + pageHeight; i >= position; i--) {
var isWrite = true
for (var j = 0; j < contentWidth; j++) {
var c = canvas.getContext('2d').getImageData(j, i, 1, 1).data
if (c[0] != 0xff || c[1] != 0xff || c[2] != 0xff) {
isWrite = false
break
}
}
if (isWrite) {
checkCount++
if (checkCount >= 10) break
} else {
checkCount = 0
}
}
height = Math.round(i - position) || Math.min(leftHeight, pageHeight)
if (height <= 0) {
height = pageHeight
}
} else {
height = leftHeight
}
canvas1.width = contentWidth
canvas1.height = height
var ctx = canvas1.getContext('2d')
ctx.drawImage(canvas, 0, position, contentWidth, height, 0, 0, contentWidth, height)
if (position != 0) {
pdf.addPage()
}
pdf.addImage(
canvas1.toDataURL('image/jpeg', 1.0),
'JPEG',
10,
10,
A4_WIDTH,
(A4_WIDTH / canvas1.width) * height
)
leftHeight -= height
position += height
if (leftHeight > 0) {
setTimeout(createImpl, 500, canvas)
} else {
pdf.save(pdfName + '.pdf')
}
}
}
// 当内容未超过pdf一页显示的范围,无需分页
if (leftHeight < pageHeight) {
// 在 pdf.addImage(pageData, 'JPEG', 左,上,宽度,高度) 设置在pdf中显示;
pdf.addImage(pageData, 'JPEG', 10, 10, A4_WIDTH, (A4_WIDTH / contentWidth) * contentHeight)
pdf.save(pdfName + '.pdf')
} else {
// 分页
try {
pdf.deletePage(0)
setTimeout(createImpl, 500, canvas)
} catch (err) {
// reject()
}
}
})
}
}
}
4.怎么使用,适用范围
上面封装的方法适用pc端和移动端,但只能在浏览器为引擎的项目,就是说在浏览器中打开此项目都是可以正常导出PDF文件的
使用方式
<template>
<div>
<div id="printer">
要导出的盒子,需要加id(printer)
</div>
<div @click="downloadHtmlToPdf">导出pdf</div>
</div>
</template>
5.问题
在浏览器打开是可以正常下载PDF文件的,但是移动端入口是从某个APP进入的,没在浏览器上运行,就会导致PDF文件直接打开的情况,但并没有下载。
导出PDF文件的方法是 pdf.save(pdfName + '.pdf') 这个方法在这种情况下导出PDF文件有问题,需要换一种写法
//pdf.save(pdfName + '.pdf')方法换成下面用a标签下载
//转成文件流的形式下载
var pdfData = pdf.output('datauristring')
var a = document.createElement('a')
a.href = pdfData
a.download = '文件名.pdf'
a.click()
a.parentNode.removeChild(a)