需求
今天收到一个需求,内容是在微信小程序点击按钮后,弹出一个动态生成的图片,并且保存在系统相册里面。
在实现过程中遇到一些坑,记录一下。
Canvas动态生成图片
第一步先在普通页面实现动态生成图片的功能,先不考虑隐藏等功能。
代码如下:
wxml:
1 | <canvas canvas-id="shareCanvas" style="width:{{canvasWidth}}px;height:{{canvasWidth*1.5}}px"> |
JS:
1 | var canvas = wx.createCanvasContext('shareCanvas') |
以上js代码就是获取canvas
控件,填充一张图做背景,然后生成文字。
然后canvas
生成图片,在成功回调方法里面保存到相册里面。
以上代码在正常页面内执行没问题。
Canvas在自定义组件内
完成了第一步后,考虑到这个按钮可能在不同的页面。就单独把上面的功能封装成一个组件。
在普通页面引入组件后,报错"canvasToTempFilePath: fail canvas is empty"
,
查阅文档后,发现createCanvasContext`
canvasToTempFilePathsaveImageToPhotosAlbum
这三个方法需要传
this这个参数。
JS`:
1 | var canvas = wx.createCanvasContext('shareCanvas',this) |
改成这样就可以了。
Canvas隐藏
现在来解决隐藏canvas
的问题。在需要的时候才会显示,类似于弹框,后面有个蒙版的样式。wxml:
1 | <view class="root" style="display:{{show}}"> |
这样我们控制root
就可以控制整个组件的隐藏和显示了。
那么问题来了,保存的图片都是空白的。获取不了canvas
的内容。如果在显示情况下没问题,当root
隐藏后就不行了。
在网上基本查到这两种解决方法:
方法一:这种方法模拟器可以,但是在真机上不行,所以这个方法放弃了。
1 | <view style='width:0px;height:0px;overflow:hidden;'> |
方法二: 这种主要是把canvas
放到无限远的位置,并且设置页面不可滚动。因为我这个是组件,所以不一定哪个页面要用,觉得比较麻烦,放弃。
1 | <view style="position:fixed;top:9999999999999rpx;"> |
那么有没有更好的解决方法呢? 我们分析一下,当root
显示的情况下canvas
这个没问题,如果root
先隐藏在显示,canvas
就会出现问题了。那么我们能不能监听root
隐藏和显示方法的事件呢?当显示完成后在去使用canvas
呢?经过一翻搜索后,好像不能监听隐藏显示。
换个思路:不监听root
的显示和隐藏,直接用setTimeout
试试呢?
1 | setTimeout(function() { |
延迟0.1秒后在操作canvas
,😆果然成功了,该死的小程序。
Canvas第一次空白
测试几次后发现第一次获取的图片还是空白的,而之后就好了。经过研究之后在canvas.draw()
回调方法里面也是延迟0.1秒后就没问题了。
1 | canvas.draw(false, setTimeout(function() { |
完整代码
JS
:
1 | make: function () { |
wxml:
1 | <view class="root" style="display:{{show}}"> |