vue中使用html2canvas将DOM转化为图片

目录
  1. 1. 一、前言
  2. 2. 二、代码
    1. 2.1. 1.安装
    2. 2.2. 2.使用
  3. 3. 常见bug
    1. 3.1. 1.生成出来的图片有白色边框
    2. 3.2. 2.有图片显示不出来并有报错(一般是跨域的错)
    3. 3.3. 3.生成图片后会在原始DOM上覆盖而产生一个闪动的效果
    4. 3.4. 4.经典版本(0.5.0)常见bug
    5. 3.5. 5.html2canvas转换的base64位图不能被ios8以上版本所识别。
  4. 4. html2canvas动态加载内容,通过canvas转换出来的数据,图片为空
  5. 5. vue中完美解决html2canvas图片跨域问题

一、前言

我发现将DOM转化为图片是一个非常常见的需求,而自己手动转是非常麻烦的,于是找到了html2canvas这个插件,既是用得比较多的也是维护得比较好的一个插件。

二、代码

1.安装

npm install html2canvas --save
现在最新的版本应该是1.0.0,另外还有一个比较经典的版本是0.5.0,网上有许多关于这个版本的bug说明。

2.使用

1
2
3
4
<img class="real_pic" :src="dataURL" />
<div class="imageWrapper" ref="imageWrapper">
...
</div>

imageWrapper里面是你需要转化为图片的DOM元素。

1
2
3
4
5
data() {
return {
dataURL: ''
}
},

dataURL是最后转化出来的图片base64地址,放在img标签中即可展示。

1
2
3
4
5
6
7
8
9
10
methods: {
toImage() {
html2canvas(this.$refs.imageWrapper,{
backgroundColor: null
}).then((canvas) => {
let dataURL = canvas.toDataURL("image/png");
this.dataURL = dataURL;
});
}
}

html2canvas的用法非常简单,不过1.0.0已经将写法改为了promise,在.then方法里获取canvas对象。

常见bug

1.生成出来的图片有白色边框

在配置项里配置backgroundColor: null即可,如果对图片宽度有要求,设置width。

1
2
3
4
5
6
7
8
9
10
11
12
13
this.$nextTick(() => {
let dom = this.$refs.imageWrapper.$refs.inviteInfo;
html2canvas(dom, {
useCORS: true, //跨域
logging: false,
allowTaint: false,
width: dom.offsetWidth, //设置canvas尺寸与所截图尺寸相同,防止白边
height: dom.offsetHeight //防止白边
}).then(canvas => {
let dataURL = canvas.toDataURL("image/png");
this.dataURL = dataURL; //需要填充的src
});
});

2.有图片显示不出来并有报错(一般是跨域的错)

这是最常见的一个bug,就是这个插件无法生成跨域了的图片,也看了官方文档配置了也百度了都没有好的办法,最后是让后端直接把跨域的图片转成base64,就完美解决了这个问题。不过图片转换成base64加增加图片文件大小,如果图片比较大,不建议转换base64,否则会增加网页加载时间,影响网站速度,这种方式一般适用于小图。

3.生成图片后会在原始DOM上覆盖而产生一个闪动的效果

先让生成的图片隐藏,等生成好以后再展示。(没有在手机上测试,效果不一定令人满意)

4.经典版本(0.5.0)常见bug

4.1.生成的图片模糊
4.2.有跨域图片导致生成的图片不完整

这两个问题网上百度都有很多解决办法。

5.html2canvas转换的base64位图不能被ios8以上版本所识别。

采用了另一款插件,dom-to-image,弄上去没有问题了。
dom-to-image运用上去,在ios上能够出现内容了,但发现存在一个问题,部分图片内容,第一次进行公众号网页加载,没有正确显示,要在次进入才会显示,此bug同样是ios8以上版本,运用dom-to-imagede toSvg方式完美解决问题。


html2canvas动态加载内容,通过canvas转换出来的数据,图片为空

问题分析:
内容是动态加载进来的,转换肯定是在请求完毕之后再去转换,但是在请求完毕之后去转换,按理说所需要的所有数据都已经到达前端,应该可以转换,经过思考,发现图片内容从后台读取需要一定时间去解析,才能够完整的将图片资源展示出来,html2canvas是将页面上显示的dom元素,经过解析将dom画在canvas上在转换为image图片格式。
解决办法:
1.让html2canvas转换代码等待一定时间,在进行转换操作,可进行转换。代码如下图所示

2.当全部的图片数据都加载完毕之后,在执行转换操作。(本人建议第二种,更保险)


vue中完美解决html2canvas图片跨域问题

html2canvas在截图的过程中,如果遇到html中有跨域地址的图片,比如图片存在了别人的云上,截图的时候将不会显示图片,解决方案如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import html2canvas from 'html2canvas'

data () {
return {
imageUrl: 'http://xxx.example.com', // 跨域地址
screenshotImage: '' // 保存的base64地址
}
},
methods: {
async shareHandle () {
const opts = {
useCORS: true
}
const ele = this.$refs.screenshot
const canvas = await html2canvas(this.$refs.screenshot, opts)
this.screenshotImage = canvas.toDataURL('image/jpg')
}
}

html代码

1
2
3
<div class="share-wrap" ref="screenshot">
<img :src="imageUrl+'?'+new Date().getTime()" crossOrigin="anonymous">
</div>

这里有几个关键的地方:

  • allowTaint: trueuseCORS: true 都是解决跨域问题的方式,不同的是使用allowTaint 会对canvas造成污染,导致无法使用canvas.toDataURL 方法,所以这里不能使用allowTaint: true
  • 在跨域的图片里设置 crossOrigin="anonymous" 并且需要给imageUrl加上随机数
  • canvas.toDataURL('image/jpg') 是将canvas转成base64图片格式。

注意:前端设置了 crossOrigin="anonymous",还需要后端配合,即请求图片返回的响应头中带有Access-Control-Allow-Origin且值为*,(允许所有网站跨域请求)或者当前网站域名(只允许固定域名下跨域请求)。

1
2
3
location ~ ^/public/.*\.(jpg|png|jpeg) {
add_header Access-Control-Allow-Origin *;
}

扩展阅读:
JS - 使用 html2canvas 将页面保存成图片
html2canvas以及domtoimage的使用踩坑总结
解锁canvas导出图片跨域的N种姿势~