一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情。
有一天接到了这样一个需求:分享列表数据,根据不同数据生成对应的卡片,要求卡片上要展示出此数据的标题、截止时间以及封面图片,如图:
经过翻阅官方文档发现:
- 分享出来的小程序卡片只能设置标题、没有副标题这一说(所以截止时间这个就不能以文字的方式设置上去了)
- 分享出来的小程序卡片只能设置一个固定的图片url 所以我们只能将截止时间与封面放到一张图片上才行,所以便有了以下基本思路:
一、分享功能的基本实现
首先,我们先来看一下分享功能的基本实现方式:
官方为我们提供了两种实现分享功能的方式
- 通过点击右上角菜单中的分享实现
- 通过点击自定义分享按钮实现
1-1、通过点击右上角菜单中的分享实现
为页面添加onShareAppMessage方法,即可开启该页面的转发功能,要注意的是此方法要返回一个对象,来自定义:
| 字段 | 说明 | 默认值 |
|---|---|---|
| title | 转发标题 | 当前小程序名称 |
| path | 转发路径 | 当前页面path,必须是以/开头的完整路径 |
| imageUrl | 自定义图片路径,可以是本地文件路径、代码包文件路径、网络图片路径。支持PNG及JPG。显示图片长宽为5:4 | 使用默认截图(分享的内容所属页面的截图) |
详情参考官方文档:onShareAppMessage
在添加onShareAppMessage之前,我们可以从模拟器上观察到,页面的分享操作是禁用的:
代码示例
onShareAppMessage() {
return {
title: '我是标题',
path: '/pages/share/index',
imageUrl: './img/aaa.jpg',
}
},
当在页面中添加上onShareAppMessage方法后,再次点击右上角的“...”,可在模拟器中观察到,页面的分享操作变成了启用状态,此时便可以进行分享啦。分享卡片内容会以方法中返回的对象中的内容进行设置。
1-2、通过自定义分享按钮实现分享
具体步骤如下:
- 首先我们要添加button组件,并为button组件设置open-type="share"属性
- 然后我们再在页面中添加onShareAppMessage方法
此时点击按钮时便可触发页面的onShareAppMessage方法,同样,要在onShareAppMessage方法中返回一个对象来配置分享出去的卡片。
下面我们来看一下常见的场景案例,以该需求为背景:
案例
现有一个“分享至微信”的按钮,点击该按钮发起分享:
由于该按钮由两部分组成,图标与文字,所以我们可以将图标与文字使用button包裹起来(这样点击图标区域或文字区域均可发起分享)
<button class="action-item" open-type='share'>
<image class="action-icon" src="./img/icon_wechat.png" style="position:relative; bottom: -20rpx;" />
<text class="text">分享到微信</text>
</button>
我们可以给button与其中内容添加类名进行样式调整:
.action-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin: 0;
background: none;
padding: 0;
font-size: 28rpx;
}
.action-item .action-icon {
width: 104rpx;
height: 106rpx;
margin-bottom: 24rpx;
}
!我们使用margin: 0; padding: 0; background: none;来去除button组件的默认样式
当我们点击按钮区域时便可触发onShareAppMessage方法
需要注意的是:
由于添加onShareAppMessage后也会启用菜单上的分享页面操作,如果只想让用户点击按钮触发分享而不启用页面菜单中的页面分享,可以在页面的onLoad或onShow方法中添加:wx.hideShareMenu() 即可
二、动态绘制分享卡片中图片内容
通过以上需求背景我们了解到,不同数据的截止时间与封面都是不一样的,所以我们要动态设置分享卡片的图片内容,由于截止时间也要显示在卡片上,但是除了title标题可以设置文字外,没有其余可以设置文字的属性,所以截止时间需要通过canvas绘制上去,那么我们可以考虑将封面图作为canvas区域的底图一同绘制上去,最后将canvas生成临时文件,将此临时文件的路径作为imageUrl就可以啦!
(需要注意的是!我们一定一定要在点击分享按钮触发onShareAppMessage方法之前将图片绘制生成好!否则在onShareAppMessage方法中将获取不到imageUrl,导致分享卡片的图片区域显示空白,所以要按照实际业务场景考虑好要在哪个时机去绘制图片~)
2-1、准备画布
<canvas wx:if="{{canvasShow}}" canvas-id="endtime" style="width: {{canvasWidth}}px;height: {{canvasHeight}}px;position: fixed; right: -999999999rpx;"></canvas>
- canvasShow用来控制canvas的显示与移除(在绘制前要将canvasShow置为true,不然绘制不上去,在绘制完毕后再将其移除)
- 要为canvas设置canvas-id,将来在获取canvas示例中使用
- canvasWidth与canvasHeight最好为5:4(官方要求,因为分享卡片的图片区域长宽比为5:4)
- 设置position: fixed; right: -999999999rpx;是为了避免在canvas绘制期间,页面会看到canvas内容(我们是不需要页面上展示出来的,只需要将绘制好的canvas变为图片然后设置到分享卡片上~)
- canvasWidth我们可以设置为设备的screenWidth,canvasHeight我们可以设置为screenWidht * 0.8,这样我们便保证了canvas的长宽为5:4
我们可以在app.js的onLaunch方法中,通过wx.getSystemInfo获取到systemInfo并设置到app的globalData中:
App({
globalData: {
systemInfo: null,
},
onLaunch: function() {
wx.getSystemInfo({
success: (res) => {
this.globalData.systemInfo = res
}
})
}
})
然后在页面中设置画布的宽高:
onLoad: function () {
this.setData({
canvasWidth: getApp().globalData.systemInfo.screenWidth,
canvasHeight: getApp().globalData.systemInfo.screenWidth * 0.8,
})
},
2-2、在点击分享按钮前绘制图片
2-2-1、使用数据封面绘制底图
绘制图片到画布上要使用:
CanvasContext.drawImage(string imageResource, number sx, number sy, number sWidth, number sHeight, number dx, number dy, number dWidth, number dHeight)
- imageResource:所要绘制的图片资源(网络图片要通过 getImageInfo / downloadFile 先下载)
- sx:需要绘制到画布中的,imageResource的矩形(裁剪)选择框的左上角 x 坐标
- sy:需要绘制到画布中的,imageResource的矩形(裁剪)选择框的左上角 y 坐标
- sWidth:需要绘制到画布中的,imageResource的矩形(裁剪)选择框的宽度
- sHeight:需要绘制到画布中的,imageResource的矩形(裁剪)选择框的高度
(详情请参考官方文档相关链接:drawImage)
由于我们数据的封面都是存于服务器上的,所以要通过getImageInfo获取图片资源再绘制:
!!需要注意的是,图片资源要以https开头,否则获取不到图片,我们可通过replace将http:// 变为 https:// (在调式模式下可以,但是在预览模式下就会发现获取不到图片了)
createImage() {
// 显示canvas画布
this.setData({ canvasShow: true })
// 获取canvas实例(此方法废弃了,但新方式暂时没研究出来如何正确使用,欢迎大家补充~)
let canvasBox = wx.createCanvasContext('endtime')
// 绘制分享底图
wx.getImageInfo({
src: this.data.operateItem.coverUrl
? this.data.operateItem.coverUrl.replace('http://', 'https://')
: '',
success: (res) => {
canvasBox.drawImage(res.path, 90, 40, 180, 234)
},
complete: () => {
// 绘制截止时间...
this.drawCanvas(canvasBox)
},
})
},
- drawImage中的图片x,y与宽高根据实际业务场景来,此处业务场景两边需要留白,所以根据绘制的图片大小设置了x y 为90 40
2-2-2、绘制截止时间(实际业务场景中要展示的文字)
由于此业务场景中不管有无获取到封面图并绘制上去,也要绘制上截止时间,所以考虑在getImageInfo方法的complete中去编写(complete无论该方法成功或失败都会触发)
drawCanvas(canvasBox) {
let _this = this
canvasBox.setFontSize(24)
canvasBox.setFillStyle('#999')
canvasBox.setTextAlign('left')
canvasBox.fillText(
`请在${this.data.operateItem.endTime}前完成`,
0,
20,
_this.data.canvasWidth
)
canvasBox.draw()
setTimeout(() => {
wx.canvasToTempFilePath({
canvasId: 'endtime',
success: (res) => {
wx.saveFile({
tempFilePath: res.tempFilePath,
success: (res) => {
_this.setData({
imageUrl: res.savedFilePath,
})
},
})
},
complete: () => {
// 删除canvas
this.setData({ canvasShow: false })
},
})
})
},
- fillText(string text, number x, number y, number maxWidth) 中的参数分别表示:所要绘制的文本、x坐标、y坐标、最大宽度
- 调取draw方法才是将文本真正去绘制上去
- wx.canvasToTempFilePath:把当前画布指定区域的内容导出生成指定大小的图片,需要传入canvas-id
- wx.saveFile:将临时文件保存至本地,保存成功后,将保存的地址信息保存下来,方便后续设置给imageUrl
- 在完成操作后,移除canvas画布
- 需要注意的是,要保证draw完毕后,才能成功将canvas上绘制的内容生成图片(所以在生成图片时加了setTimeout)
至此我们的前置工作就做好啦,我们下面只需在点击按钮时触发的onShareAppMessage方法中设置上需要设置的卡片内容即可!
2-3、通过onShareAppMessage给分享卡片设置内容
onShareAppMessage() {
return {
title: 'xxxx',
path: `/pages/share/index?id=${this.data.operateItem.id}`,
imageUrl: this.data.imageUrl,
}
},
需要注意的是,模拟器下是看不到分享卡片上生成的图片的,需要在真机上测试! 至此,我们便可根据不同数据来生成属于该数据的分享卡片了~