1.安装包
npm i html2canvas jspdf -S
2.新建类文件to_pdf.js
因为要处理分页,所以这个版本是做分页处理的
import html2canvas from "html2canvas";
import JsPdf from 'jspdf'
class ToPdf {
constructor (id, title) {
this.id = id
this.title = title
}
/**
* 获取需要打印的页面dom元素
* @param id
* @returns {Promise<HTMLCanvasElement>}
*/
getCanvas(id) {
// window.devicePixelRatio为浏览器设备像素比率
// 设置dpi和scale越高,图片越清晰,相对的文件也会越大,一般设置为两倍,清晰度就可以了
return html2canvas(document.querySelector(`${id}`),
{
dpi: window.devicePixelRatio * 2 || 2 // 放大两倍
scale: window.devicePixelRatio * 2|| 2, // 按两倍缩放
useCORS :true, // 支持跨域
allowTaint: false,
}).then((canvas) => {
return Promise.resolve(canvas)
})
}
/**
* 处理页面,绘制成图片
* @returns {Promise<boolean>}
*/
async toCanvas() {
let canvas = await this.getCanvas(this.id)
let context = canvas.getContext('2d')
// 【重要】关闭抗锯齿
context.mozImageSmoothingEnabled = false;
context.webkitImageSmoothingEnabled = false;
context.msImageSmoothingEnabled = false;
context.imageSmoothingEnabled = false;
// 当前生成dom生成的canvas的宽高
let contentWidth = canvas.width
let contentHeight = canvas.height
// 按照a4纸比例计算当前宽度下,生成的一页高度
let pageHeight = contentWidth / 592.28 * 841.89
// 即将生成pdf的页面canvas总高度
let leftHeight = contentHeight
// 页面偏移量,分页用
let position = 0
// a4纸的尺寸595.28 * 841.89,html页面生成的canvas在pdf中图片的宽高
let imgWidth = 595.28
let imgHeight = imgWidth / contentWidth * contentHeight
let pageData = canvas.toDataURL('image/jpeg', 1.0)
let PDF = new JsPdf('', 'pt', 'a4')
if (leftHeight < pageHeight) { // 当内容未超过pdf一页显示的范围,无需分页
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()
}
}
}
PDF.save(this.title + '.pdf')
// return true
}
}
export default ToPdf
3. 在需要转pdf的页面,导入
3-1. 确认dom
html页面
<template lang="pug">
div#report-wrapper
span.print-button(@click="printPdf()") 打印
div.report-right
div.report-right-box
</template>
<script src="./control.js"></script>
<style scoped lang="stylus" src="./style.styl"/>
3-2. 导入类,并使用
js页面
import ToPdf from "../../utils/to_pdf";
export default {
data () {
return {
};
},
watch: {
},
computed: {},
methods: {
/**
* 保存为pdf
*/
printPdf() {
let pdf = new ToPdf('.report-right-box', '打印')
let flag = pdf.toCanvas()
console.log('flag', flag)
},
},
components: {
},
mounted () {
}
};
正常到这里就结束了,但是事情其实不会这么简单就结束,肯定会报错的
我们还需要处理
跨域问题
4. 处理图片跨域
4-1. 使用nginx,则要配置
在conf里面找到server,然后增加以下代码
if ($request_method = 'OPTIONS') {
return 204;
}
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, PATCH, DELETE, HEAD" always;
add_header Access-Control-Max-Age 86400 always;
然后需要重启nginx,记住了
如果后台是java 解决跨域问题:No 'Access-Control-Allow-Origin' header is present on the requested resource.
4-2. 网络图片或者本地图片转为base64
新建common.js文件
/**
* 网络图片转base64
* @param {String} imgUrl 图片地址
*/
export const networkImg2Base64 = (imgUrl) => {
return new Promise((resolve, reject) => {
let image = new Image()
image.crossOrigin = '*' // 跨域
image.onload = function() {
// 用canvas把图片转成base64
let canvas = document.createElement('canvas')
canvas.width = image.width
canvas.height = image.height
let ctx = canvas.getContext('2d')
ctx.drawImage(image, 0, 0, image.width, image.height)
try {
let base64 = canvas.toDataURL('image/png')
resolve(base64)
} catch (error) {
reject('浏览器不支持canvas转base64')
}
}
image.onerror = function() {
reject('图片加载失败')
}
// 一定要加后面的随机数,不然跨域解决不了
image.src = imgUrl + '?v=' + Math.random();
// 给图片地址添加时间搓参数
// image.src = UrlUtils.addParameter(imgUrl, {
// v: new Date().getTime() // 处理缓存,防止304
// })
})
}
4-3. 在页面中处理图片
import ToPdf from "../../utils/to_pdf";
import {networkImg2Base64} from '../../utils/common'
export default {
data () {
return {
companyImage: 'https://www.xxxxxx.com/images/xxxxx.png',
bgImage: 'https://www.xxxxxx.com/images/pdf_1.png',
};
},
watch: {
},
computed: {},
methods: {
/**
* 保存为pdf
*/
printPdf() {
let pdf = new ToPdf('.report-right-box', '打印')
pdf.toCanvas()
},
/**
* 图片转base64
*/
async toBase64() {
this.bgImage= await networkImg2Base64(this.bgImage)
this.companyImage = await networkImg2Base64(this.companyImage)
}
},
components: {
},
mounted () {
this.toBase64()
}
};
5. 参考资料
html2canvas踩坑记录
JsPDF + html2Canvas 网页导出pdf
纯前端html导出pdf--分页+不分页--html2canvas+jsPDF
解决跨域问题:Nginx提示CORS
跨域配置(解决CORS报错)
6. 问题
6.1 文字偏移
假如用了tailwindcss,其中的 base有个img设置了display:block导致的,全局重置即可
img { display: initial; }
或者设置html2canvas版本号为1.0.0
还有其他方式自己看:issues