应用场景
场景1:线上域名与图片域名不一样。
出现错误:Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
场景2:线上域名是 https
,图片的域名是 http
。
出现错误:Redirect from 'http://cdn.******.cn/1551270315991.jpeg' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://h5.******.cn' is therefore not allowed access.
解决思路
- 图片的
crossOrigin
设置为*
- 图片
URL
添加随机参数 - 图片转为
base64
图片
核心代码
image.crossOrigin = '*'
this.$utils.addURLParam(elem.src, new Date().getTime())
this.getBase64Image(image)
完整参考代码(Vue)
我的业务场景是生成宣传海报,执行 create()
方法
// 转为 base64 图片
getBase64Image(img) {
let canvas = document.createElement('canvas')
canvas.width = img.width
canvas.height = img.height
let ctx = canvas.getContext('2d')
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
let dataURL = canvas.toDataURL('image/png') // 可选其他值 image/jpeg
return dataURL
},
// HTML 转成画布,生成图片
getPoster() {
window.scrollTo(0, 0) // 修复上边有空白 BUG,https://github.com/niklasvh/html2canvas/issues/1878
// http://html2canvas.hertzen.com/configuration/ 配置设置地址
let opts = {
scale: 4, // 画布像素大小。默认为浏览器设备像素比。
// logging: true, // 日志开关,便于查看 html2canvas 的内部执行流程
useCORS: true, // 【重要】开启跨域配置
allowTaint: true, // 【重要】开启画布污染
backgroundColor: '#0000'
}
this.$html2canvas(this.$refs.createContainer, opts).then(canvas => {
this.posterUrl = canvas.toDataURL('image/jpeg') // 默认转化的格式为 png,也可设置为其他格式
this.$loading().close()
})
},
// 生成海报
create() {
this.$loading({
showMask: true,
text: '正在生成海报...'
})
let imgs = this.$refs.createContainer.querySelectorAll('img')
let count = 0 // 计数用
// 排除 base64 图片,因为 base64 图片无跨域问题
imgs = Array.from(imgs).filter(elm => {
return elm.src && !/^data:image\/png;base64/.test(elm.src)
})
if (imgs.length > 0) {
// 将会跨域的图片转为支持跨域 base64 图片,最后再执行 html2canvas
imgs.forEach((elm, index, arr) => {
let image = new Image()
image.crossOrigin = '*' // 支持跨域图片
image.src = this.$utils.addURLParam(
elm.src,
'date=' + new Date().getTime()
) // URL 添加随机参数,使 onload 生效
image.onload = () => {
elm.src = this.getBase64Image(image) // 移动端还需要转为 base64 图片
count++
// 全部图片加载完毕
if (count === arr.length) {
this.getPoster()
}
}
})
} else {
this.getPoster()
}
}
工具方法 this.$utils.addURLParam()
/**
* 添加 URL 参数
* @param {String} url 链接,默认 window.location.href
* @param {String} param 参数,例 id=1
* @return {String} 新的 URL
*/
export const addURLParam = (url = window.location.href, param) => {
let parmas = new URLSearchParams(url.split('?')[1])
return url + (parmas.toString() ? '&' : '?') + param
}