最近接到的一个新需求:页面一个静态H5,中间有一页是输入信息,然后跳转到最后一页,自动将页面生成图片,用户可以长按图片保存到手机上。
展示一下最后一页的样子:
刚拿到这个需求,在网上看了很多文章,最普遍的是使用 html2canvas + canvas2image 来实现。于是,跟着前人的脚步,踏上了一个不断采坑采坑采坑的旅程。
下面直接描述我在做这个需求过程中遇到的问题以及解决办法吧:
1.html2canvas 图片跨域:
这个问题网上很多解决办法:
这个是最常用的, 刚开始我只是加了红色框里面的这一句,但是并没有任何作用,依旧报错。后来看到有人说,加上前面那一句,所以果断在加进去。
这两句其实表达的是同一个意思:允许图片跨域。
当然,也有网友说,直接给一个空值就可以,我当时试了一下,并不ok~~~~.
2.多次使用canvas drawImage 方法图片展示问题
2.1 图片加载顺序问题
在我这个需求里面,肯定是文字描述以及二维码是展示在图片上面的,刚开始我是
1. drawImage 文字,
2. drawImage 二维码
3. drawImage 背景大图
然而,结果让我大吃一惊,只有背景图加载渲染出来了。然后,通过无所不能的网络才知道:drawImage 的顺序应该是:图片最底下的需要最先加载渲染。
2.2 图片显示不完整
在2.1 问题出现的同时还遇到了这个问题,图片渲染不完整,这。。nima。。。需求才刚开始做,怎么这样为难一个小女子。。。
不过有问题嘛,就解决咯。
图片渲染不完整,原因就是:在图片还没有加载完成的时候,canvas 就开始进行渲染。
因此解决办法就是:等图片加载完成后再进行drawImage 操作就可以啦,上~~~~代码:
3.canvas 保存为图片的跨域问题
遇到这个问题,我真的是花了一堆一堆的时间来看文章,看博客,,。
这会万能的网友给我的解决办法并没有任何效果:
他们说:1.把图片取下来放在自己服务器上(我用的公司的图片服务器。但是和我的放代码服务器不是同一个地址啊)
2. 用canvas2Image 啊,然而,,这不也是跨域么,,并没有啥,,用。
3.还有啥来着,,忘了,反正那天搞得我精神崩溃,,,也没解决到问题,,后来实在忍不住,问了公司的大神:大神说:你用base64 的呢。。
一语惊喜梦中人,对啊,这种方法多棒,这样就不会跨域了啊。当时为了赶进度,直接在线吧图片转成basa64 ,然后存成一个js 文件。
当时是这样的:红框里表示的是文件的格式。。、
至此,我的html 已经转为canvas 并且从canvas 转为img 存在页面上了,,
后来我在看这一段,觉得似乎不太好,这个文件显得很大,所以我想在用这个文件的时候在把它转成base64 的格式,,
1.利用canvas todataUrl 将图片转为base64
但是这种方法不可避免的会出现跨域的问题,pass
2.base64.js
这个文件中中文转码会出问题,而且我试过了,基本的字符串转码都是ok 的,但是对于文件转码就会出问题
3.浏览器原生的并且都支持的一个东西: window.atob and window.btoa
window.atob 是将base64 格式转换为字符串或者二进制编码格式
window.btoa 是将字符串或者二进制编码 格式转换为base64 格式 所以上面的base64.js 真的,,别浪费时间精力去看了,,
那文件编码解码呢?
原生的也有方法:FileRender() 这个构造函数,
var reader = new FileReader();
reader.onload = function(e) {
// e.target.result
};
reader.readAsDataURL(file);
这种方法没有测试过o(╥﹏╥)o。。
所以,目前为止,需要把文件转为base64. 格式的,我并没有找到合适的方法或者js 插件来操作,如果各位有什么好的办法,麻烦告诉我(* ̄︶ ̄)。
4. 图片模糊并且窗口中只显示了一部分
才定义canvas 的时候,我是给canvas 定义了一个宽高的,宽高是背景图的大小,因此在drawImage 的时候是按照canvas 实际尺寸进行渲染。
但是转为图片的时候是按照窗口的尺寸来进行的,因此图片会模糊,如果给图片设置canvas 宽高的话,图片在窗口中又显示不完整。
因此,就需要计算设备的retio,
基本思路:计算出ratio ---> 然后canvas 转 img (按照canvas 实际尺寸进行渲染) ---> 图片按照窗口大小进行缩放
这个方法直接返回的是设备的ratio..
然后我们在进行canvas 渲染的时候,
在后面进行图片渲染的时候,图片的宽度直接除以 ratio ,这样图片就能完整的显示在窗口中。
5. ios10.2 canvas 转图片 一片黑
至此,页面是呈现出来了,并且在我的安卓(华为)上测试是ok
但是需求的同学(ios)告诉我:她的手机上最后一页是黑色的和,顶部有个白色框,,,我一懵,天,不会ios 不支持吧。
于是,用了旁边座位同学的手机。恩,也不行。。
啊啊啊啊啊,要崩溃。
在网上看了一下,有一种解决办法就是:使用双缓冲(出现黑屏的可能就是在drawImage 的时候计算量很大,然后渲染卡顿不成功)
大概思路就是:在新建一个cachecanvas 刚开始其实是把图片渲染在这个缓存的canvas 中的,然后在将cachecanvas 中的内容渲染到需要在页面展示的canvas 中。
我在中间使用了一个延时,时间虽然很短,但是这样也能确保cachacanvas 确实渲染完成在进行正式的canvas 渲染。
这样,我周围座位上的ios 上最后一页都能显示出来了,,但是那个ios10.2 的依旧不行,,啊,网上查了一下,这个版本的问题一直存在,所以,(꒦_꒦) ,
就这样,这个需求在我不断采坑的过程中,好像也快完结了,这里很少直接贴代码进来,因为贴进来似乎看的不太好,所以我基本上是截图的。
最后,几个小tips :
1.直接将网页图片存成base64 格式的,如果图片很少,可以,如果图片很多,还是建议不要这么操作了,比较一个base64的数据格式就已经很大了。。。
2.图片先压缩,然后在进行base64格式编码吧
3.对于drawImage 的位置,是相对于canvas 实际尺寸的。所以如果使用百分比,建议先得到窗口的宽高,然后在进行赋值。
4. 在使用canvas fillText 的时候,有一个限制最大宽度,就是fillText 的最后一个参数(直接写数值即可,不用带单位,默认似乎是px)。
5.对于一般的H5,还是对图片进行预加载一下吧,。。(网上很多图片预加载的方法,自行查找哦)。