前言:
有些时候需要再小程序中分享一些动态生成的图片,比如页面截屏、商品卡片,虚拟卡券等等。但是小程序都没有开放页面截屏接口的,最多也就是提供设备截屏事件监测的API。所以,基于目前的情况,小程序对页面进行截屏,本身就是个伪命题,能做的只有用现有技术去模拟了。
要解决这个问题,目前除了canvas画布合成,没有其他什么比较好的解决方法。这里就介绍下微信小程序中使用canvas来模拟页面截屏并分享的功能。具体代码如下:
index.wxml
1 <!--动态合成图片的画布-->
2 <canvas canvas-id="shareBox"></canvas>
3 <!--动态合成图片的画布end-->
4 <!--页面展示部分-->
5 <view id="content">
6 <view class="f0"><image class="goodsImg" src="/imgs/demo.jpg"></image></view>
7 <view class="goodsTitle">
8 <view class="goodsName">哈根达斯 298元冰淇淋蛋糕</view>
9 <view class="goodsPrice">298.00元</view>
10 </view>
11 </view>
12 <!--页面展示部分end-->
index.js
1 const app = getApp()
2 //尺寸比例计算(页面宽度已750为准,即750*scale,所有尺寸乘以scale,即可兼容各种大小屏幕)
3 const scale = wx.getSystemInfoSync().windowWidth / 750
4 Page({
5 data: {
6 shareUrl: ""
7 },
8 onLoad(e) {
9 },
10 onReady: function() {
11 this.drawShareImage()
12 },
13 drawShareImage() {
14 //绘制canvas图片
15 //创建一个canvas对象
16 const ctx = wx.createCanvasContext('shareBox', this);
17 // this.drawNormalText(ctx, "canvas生成的图片", 0, 0, 30, '#ffffff', 'left', 'middle')
18 //商品主图
19 var bgSize1 = 750 / 500
20 this.drawImage(ctx, "/imgs/demo.jpg", 20, 20, 710, 710 / bgSize1);
21 //绘制商品标题部分
22 var bgSize2 = 750 / 246
23 this.drawImage(ctx, "/imgs/detail-name-bg.jpg", 20, 490, 710, 710 / bgSize2);
24 //绘制分享标题
25 this.drawNormalText(ctx, "canvas生成的图片", 50, 548, 30, '#ffffff', 'left', 'middle')
26 this.drawNormalText(ctx, "230.00元", 50, 660, 30, 'red', 'left', 'middle')
27 this.drawNormalText(ctx, "230.00元", 50 + 1, 660, 30, 'red', 'left', 'middle')
28 this.drawNormalText(ctx, "230.00元", 50, 660 + 1, 30, 'red', 'left', 'middle')
29 this.drawNormalText(ctx, "230.00元", 50 + 1, 660 + 1, 30, 'red', 'left', 'middle')
30 //绘制canvas标记(绘制圆形并加阴影)
31 ctx.arc(120 * scale, 120 * scale, 80 * scale, 0, 5 * scale * Math.PI)
32 ctx.setFillStyle('#22aaff')
33 ctx.setShadow(0, 0, 20 * scale, "#aaaaaa")
34 ctx.fill()
35 this.drawNormalText(ctx, "Canvas", 118, 100, 30, 'white', 'center', 'middle')
36 this.drawNormalText(ctx, "合成", 118, 140, 30, 'white', 'center', 'middle')
37
38 //绘制画布,并在回调中获取画布文件的临时路径
39 var self = this
40 ctx.draw(true, function() {
41 wx.canvasToTempFilePath({
42 canvasId: 'shareBox',
43 success(res) {
44 console.log(res)
45 if (res.tempFilePath) {
46 self.setData({
47 shareUrl: res.tempFilePath
48 })
49 wx.setStorageSync("shareUrl", res.tempFilePath)
50 }
51 }
52 })
53 });
54 },
55 //绘制图片封装
56 drawImage(ctx, url, x, y, w, h) {
57 ctx.drawImage(url, x * scale, y * scale, w * scale, h * scale);
58 },
59 // 绘制只有一行的文字
60 drawNormalText(ctx, str, x, y, font, style, align, baseLine) {
61 ctx.setFontSize(font * scale);
62 ctx.setFillStyle(style);
63 ctx.setTextAlign(align);
64 ctx.setTextBaseline(baseLine);
65 ctx.fillText(str, x * scale, y * scale);
66 },
67 //onShareAppMessage(res) {}
68 })
注意事项:
1.canvas中并没有类似rpx之类的自适应单位,所以需要提前定义好页面尺寸比例,有利于实现不同屏幕兼容性。具体代码如下:
const scale = wx.getSystemInfoSync().windowWidth / 750
2.canvas中的所有尺寸以750为标准,即一般设计稿的尺寸即可,实际绘制中所有尺寸乘以尺寸标准就可以适应所有尺寸屏幕了。如有需要,可以对某些绘制逻辑进行函数封装,如文本、图片。
1 //绘制图片封装
2 drawImage(ctx, url, x, y, w, h) {
3 ctx.drawImage(url, x * scale, y * scale, w * scale, h * scale);
4 },
5 // 绘制只有一行的文字
6 drawNormalText(ctx, str, x, y, font, style, align, baseLine) {
7 ctx.setFontSize(font * scale);
8 ctx.setFillStyle(style);
9 ctx.setTextAlign(align);
10 ctx.setTextBaseline(baseLine);
11 ctx.fillText(str, x * scale, y * scale);
12 },
后记:
1.使用canvas进行页面合成并生成图片是有点麻烦,需要把页面元素进行一一绘制,但是,这个是目前模拟页面截屏切实可行的方法。不要说要截取的页面比较长什么的,不少h5的游戏都是canvas做的,怎么说也比普通页面复杂吧。当然了,这也是没办法中的办法,如果哪天小程序开启了截屏权限,那么自然就不用这么折腾了。
2.本例中关于页面分享的相关实例,可以参考:微信小程序分享转发用法大全——自定义分享、全局分享、组合分享。