移动端 html2canvas 踩坑记录

背景

最近在做的微信 html5 项目有个需求:页面包含 一张大的背景图片 + 一个用户的链接二维码图片 拼成一张图片,让用户长按保存的时候,可以把整个页面都保存起来,而不是只保存二维码。

思考

1.前后端哪个实现方法会更高效

虽然图片都可以从后台获取,但是一来需要 等待二维码生成->添加到大图上->转换成一张图片->传输,是一个同步过程,耗时比较久;二来看到网上的评价,后台使用的库生成的图片偶尔会出错,修改起来也麻烦。因此决定在前端完成。

2.使用 svg 还是 canvas

考虑到移动端对 html5 新特性支持得比较好以及高分辨率屏幕,使用 svg 看起来很适合------如果没看到前辈的踩坑文章的话,会是这样的~~

根据 https://www.jianshu.com/p/458... 所说,步骤是 html-->svg-->canvas-->img ,问题出在使用跨域图片的时候:

移动端 html2canvas 踩坑记录

也即是 iphone 系列都被拒之门外 ...

因此决定用 html2canvas 库,完成 html-->canvas-->img 的转变。以下是踩坑心得。


坑一

图片模糊

此为想不到的坑,浪费了很多时间在代码检查上...

移动端 html2canvas 踩坑记录

问题: html2canvas 渲染背景图片 background-image 会不清晰。

解决方法:使用 Img 标签。

坑二

高分辨率下,文字模糊

此为预料中的情况,获取了设备像素比 window.devicePixelRatio 百分比伸展 canvas 画布即可......才怪......

然后发现这是 0.5 版本需要做的操作,1.0 版本的默认参数 scale 已经设置好了,但还是不太清晰。

最后从同事处得到启发,最终解决方法是!!

一律设为 4 倍!即

html2canvas(ele, {
    sacle: 4
}).then((canvas) => {});

简单粗暴...虽然图片体积因此变大了...

坑三

IOS 下,概率性出现大图绘制不出来的情况

对于这个需求,原本的操作是在 img 标签里的 src 属性写上大图链接,在 activated() 里生成二维码再创建新的 img 标签附到大图里(用的 vue)。在 IOS 上,经常出现页面上只有背景颜色和二维码的图片的情况。

原因: 大图还未下载完毕即开始了绘制。

解决方法: 给 img 添加 onload 事件,下载完毕再调用绘制方法。

坑四

html 元素的隐藏

因为是要让用户长按保存整个页面,所以用 html2canvas 将所有内容转成图片。而其并不能绘制隐藏的内容,因此需要先显示页面,在图片生成后再隐藏。在 vue 里就是 v-show 的值的变化过程。

问题: 页面会有闪烁,再显示图片

解决方法: 组件直接设为 v-show = false,html2canvas 添加参数 onclone ,生成一个复制的虚拟组件,设置为显示,即可获取进行绘制,且虚拟组件不会显示在页面上。

html2canvas(ele, {
    onclone(doc) {
        let e = doc.querySelector('#wrapper');
        e.style.display = 'block';
    }
}).then((canvas) => {});

其他坑

图片高度

问题: UI 只给了一张图片,宽度可以稍微拉伸,高度在全面屏下会不足以覆盖整个屏幕,漏出白底;强制设置为屏幕高度图片会失真。

解决方法: 让 UI 帮忙别把图片底部设计得五颜六色,只保留一种颜色。然后将页面的背景颜色设为同种颜色即可。

二维码图片的位置定位

问题: 如何让二维码图片在不同屏幕下都定位到正确的位置。

解决方法: 设为绝对定位,使用屏幕宽度作为基准设置 left、top 值。

.qr {
    width: 32vw;
    position: absolute;
    left: 16vw;
    top: 97vw;
}

图片跨域等

其他更多类似图片跨域等问题可以参考以下两篇文章:

http://www.php-master.com/pos...

https://www.jianshu.com/p/458...

相关推荐