canvas2html 遇到的跨域问题
2021-09-05 本文已影响0人
佳瑞Jarrett
背景:
当我们出现vue页面需要保存为pdf文件时,网络上提供的办法几乎都是如下。
使用html2canvas 以及jspdf 两个库。
// 导出页面为PDF格式
import html2canvas from 'html2canvas'
import JSPDF from 'jspdf'
export default {
install(Vue, options) {
Vue.prototype.ExportSavePdf = function (htmlTitle, currentTime) {
var element = document.getElementById('pdfContent')
html2canvas(element, {
logging: false
}).then(function (canvas) {
var pdf = new JSPDF('p', 'mm', 'a4') // A4纸,纵向
var ctx = canvas.getContext('2d')
var a4w = 170;
var a4h = 257 // A4大小,210mm x 297mm,四边各保留20mm的边距,显示区域170x257
var imgHeight = Math.floor(a4h * canvas.width / a4w) // 按A4显示比例换算一页图像的像素高度
var renderedHeight = 0
while (renderedHeight < canvas.height) {
var page = document.createElement('canvas')
page.width = canvas.width
page.height = Math.min(imgHeight, canvas.height - renderedHeight) // 可能内容不足一页
// 用getImageData剪裁指定区域,并画到前面创建的canvas对象中
page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)), 0, 0)
pdf.addImage(page.toDataURL('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()
} // 如果后面还有内容,添加一个空页
// delete page;
}
pdf.save(htmlTitle + currentTime)
})
}
}
}
- 这段代码的原理是首先创建canvas对象,然后利用
ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)
按照设定的长宽尺度将页面保存为图片,最后将保存的图片塞到pdf文档中。 - 该方法对于常规页面来说,都可以很好的保存下来。但是无法很好的支持某些dom分段分页,因为它是按照长宽尺寸进行裁剪的,无法对表格图片等很好的识别进行分段保存。而且保存下来的文字等信息是无法选中的,产生的原因同样是保存下来的文档里其实都是图片。
产生了新的问题
在我的页面中引用了第三方的图片地址,而且这些第三方图片是不固定的。再到处这些图片为dpf时,总是会出现如下问题:
Uncaught SecurityError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.
问题原因
在网页的html中引入第三方的图片,导致出现了无法截图的问题。
解决问题
使用浏览器自带的打印功能,将页面保存为pdf。相比于原来需要解决跨域问题,该种方法不需要进行设置;但该方法每次在导出pdf的时候,需要进行预览后保存;保存下来的文字图片是可以被选中的;页面中会出现一些附属信息,例如网址,日期,页码等;页面同样对表格、图片等无法做到很好的分段分页等。
// 1.设置要打印的区域 div的className
var newstr = document.getElementsByClassName('printOrder-data')[0].innerHTML
// 2. 复制给body,并执行window.print打印功能
document.body.innerHTML = newstr
// 3. 还原:将旧的页面储存起来,当打印完成后返给给页面。
var oldstr = document.body.innerHTML
window.print()
document.body.innerHTML = oldstr
总结
各种方法有利有弊,需要结合业务的实际情况,做出一些调整。
如果您觉得上面的内容对您有帮助欢迎点赞、评论、转发!
更多内容请查阅作者博客:https://jiaruiblog.com
或者star
作者github: https://github.com/Jarrettluo?tab=repositories