在小程序里,我们知道分享功能只有分享到微信好友或者群,无法直接分享到朋友圈,但是我们可以生成分享图片,然后保存到相册,在发布朋友圈从相册选择图片,所以关键是如何生成需要的图片,使用 canvas 画布即可实现。
canvas 是微信小程序里的原生组件,相关属性及注意事项可参考 小程序官方文档 。一般生成分享图片需要显示文字和相应的图片,在结合不同位置和不同大小的需求形成特定样式的图片。
首先需要在 wxml 里写 canvas 的布局,例如:
<view class="canvas-box">
<canvas style="width: {{sysWidth}}px;height: {{canvasHeight}}px;" canvas-id="shareCanvas" />
</view>
为什么我会在 canvas 控件外在加一个 view ,这个跟需求有关,后边再说,如果只需要合成一张图并不需要分享或者点击预览大图的话可以只用一个 canvas 布局。我这里宽高都是计算出来的,因为生成的图片有要求,canvas 标签默认宽度300px、高度225px。canvas-id 是对应的每个画布的 id ,同一页面中的 canvas-id 不可重复,如果使用一个已经出现过的 canvas-id,该 canvas 标签对应的画布将被隐藏并不再正常工作。
我当时的需求是在商品详情页点击分享按钮自动生成商品对应的分享图片,图片需要包含商品标题、价格、商品展示图片、商品详情页面的二维码(扫码可以直接进入当前商品详情),使用画布首先需要初始化画布,
const canvasCtx = wx.createCanvasContext('shareCanvas'); //shareCanvas 是画布的 id
然后绘制背景,如果想绘制一个宽高为屏幕宽度和屏幕高度的白色背景画布,可以这样写:
canvasCtx.setFillStyle('white');
canvasCtx.fillRect(0, 0, this.data.sysWidth, this.data.sysHeight);
开始绘制商品标题,
canvasCtx.setFontSize(18);//字体大小
canvasCtx.setFillStyle('#f9555c');//字体颜色
canvasCtx.setTextAlign('left');//字体对齐方式
canvasCtx.fillText('这是商品标题', 20, 30);//20是 x 轴的坐标,30 是 y 轴的坐标,以此确定字的位置
说一下字体对齐方式,left 表示商品标题的最左端坐标为 x 轴的坐标,也就是上边的20,如果对齐方式是 right 表示商品标题的最右端坐标为 20,不管标题多长结尾处都在20坐标点,center 表示标题的居中位置在20,即 x 轴上商品标题是以20作为对称点的。这点需要知道,否则想当然的认为是相对屏幕居左、居右、居中对齐就不对了。
接下来画图,使用 CanvasContext.drawImage 方法,如下
canvasCtx.drawImage(imgUrl, xPoint ,y, 120, 120); //图片路径,x轴坐标,y轴坐标,图片宽,图片高
跟文字相似,只是方法不同,最后需要加上
canvasCtx.draw() //将之前在绘图上下文中的描述(路径、变形、样式)画到 canvas 中。
这样就完成了在画布上成功生成图片的功能。
但是用画布生成图片还不行,由于在 canvas 上画图后图片只是显示在画布上,不是使用 image 展示,也就不能直接保存图片到相册,同时由于 canvas 是原生组件,显示在布局中会覆盖其他控件,所以可以隐藏 canvas ,但是 canvas 仍会占据空间位置,所以上边我在 canvas 外边加了一个 view 父布局,父布局属性如下,top 是为了让 canvas 距离顶端足够大,以隐藏 canvas ,如果使用 hidden 隐藏会仍占据位置,有空白区域。
.canvas-box {
position: fixed;
top: 99999px;
left: 0;
}
最后需要将画布上的图片转换成图片,小程序官方提供了一个这样的方法:wx.canvasToTempFilePath ,可以直接得到一个图片路径,将此图片路径赋值给 image 组件再显示最终的图片。举个栗子?
setTimeout(function() {
wx.canvasToTempFilePath({
canvasId: 'shareCanvas',//定义的 canvas 的 id
success: function(res) {
var tempFilePath = res.tempFilePath;
console.log("合成图片", tempFilePath)
self.setData({
shareImage: tempFilePath,
})
},
fail: function(res) {
wx.hideLoading();
console.log('生成失败', res)
}
})
}, 50);
wxml 布局里需要一个 image 组件展示生成的图片
<image style="height: {{canvasHeight}}px;" mode="widthFix" class='share_image' src='{{shareImage}}' />
上边转换的地方加了一个 setTimeout 定时器,在定时到期以后执行注册的回调函数,防止画布在 draw() 的时候没有完成就执行转换图片的方法会导致生成失败的问题,所以加了一个延迟。
最后如果需要直接帮用户保存此图片,可以使用 wx.saveImageToPhotosAlbum 方法,注意调用前需要用户授权。
生成的图片如下(仅供参考):
以上就是生成图片的方法,写的比较啰嗦,其实没有多麻烦,第一次接触可能感觉比较复杂,但是总代码量很少,有不懂的可以留言回复,感谢观看。