关于html转canvas遇到的坑(vue)
转换插件:html2canvas
html2canvas如何使用我就不介绍啦,很简单,网上一搜啥都有,主要就是坑多。
坑1:跨域
当dom元素里面包含远程图片时,转换会出现跨域错误。其实就是html2canvas插件在将图片转为canvas的时候跨域了,所以就算不用html2canvas插件也会遇到这个问题。
解决方式分3步:
第一步:需要后端设置Access-Control-Allow-Origin的值为“*”,允许该图片跨域。我用的是oss图片,所以需要到oss服务器修改跨域设置如下:
第二步:需要前端设置 crossorigin="anonymous"允许该图片跨域,如:
<template>
<div ref="dom">
<div>dom转canvas</div>
<img id="test" src="https://whbj-oss-dev.oss-cn-shenzhen.aliyuncs.com/pt-tms/20210331/202103311117569924.png" crossorigin="anonymous" alt="">
</div>
</template>
注意:这里设置完 crossorigin="anonymous"之后一定要清除一下浏览器缓存,否则还会报错,我被这个问题困惑了很久,还一直以为是oss设置有问题。
如果浏览器审查该元素能看到Access-Control-Allow-Origin:*,则表示跨域设置生效了,如下图:
第三步:需要将html2canvas的useCORS属性设置为true允许跨域,如:
domToCanvas(){
html2canvas(this.$refs.dom,{
allowTaint: false,
useCORS: true
}).then(canvas => {
// 将canvas对象转化为image/png
var imgUrl = canvas.toDataURL('image/png')
console.log('dom转canvas成功:', imgUrl)
}).catch(err=>{
console.log('err:'+err)
});
}
坑2:ios平台不可用
跨域问题解决后,谷歌运行转换一切顺利,结果嵌入APP后在iOS平台就不起作用了,安卓正常。
解决方式是:使用html2canvas1.0.0-rc.4版本,vue环境下运行:
npm uninstall html2canvas
npm i html2canvas@1.0.0-rc.4;
坑3:有些图片可以转换成功,有些又不行,或者转换后缺了一块。
一般是由于dom还没有渲染完成引起的。
解决方式是:将转换方法放到mounted或者.$nextTick方法中,即等待dom渲染完成后再转换。
如果还不行,使用setTimeout加一个延时,如:
created() {
let that = this;
this.$nextTick(async ()=>{
setTimeout(function() {
that.domToCanvas();
}, 100);
})
},
坑4:转换方法有时调用有时不调用
一般是由于图片缓存引起的,比如进入页面后转换一次成功,点击某按钮后刷新页面,再转换一次很可能就不调用了。
解决方案是:给图片拼接时间戳,防止图片缓存。如:
var timestamp = (new Date()).getTime(); //时间戳
var src = "https://whbj-oss-dev.oss-cn-shenzhen.aliyuncs.com/pt-tms/20210331/202103311117569924.png";
src = src + '?' + timestamp;
坑5:转换后的图片模糊
这个主要是由于图片没有使用img标签,比如,通过background设置背景图,转换就会模糊,使用img标签就好了。
坑6:转换后的图片不透明
这个是因为html2canvas默认转换后的图片背景为白色,如果想要透明,设置backgroundColor属性为null即可,如:
domToCanvas(){
html2canvas(this.$refs.dom,{
allowTaint: false,
useCORS: true,
backgroundColor: null
}).then(canvas => {
// 将canvas对象转化为image/png
var imgUrl = canvas.toDataURL('image/png')
console.log('dom转canvas成功:', imgUrl)
}).catch(err=>{
console.log('err:'+err)
});
}