这里是
Geek
小程序的源码,点击查看 github 源码
前言
在开发小程序的过程中,你是否有将页面生成分享图并引导用户转发至朋友圈的需求?有,那就进来看看,应该是你想要的结果。
在分享上,就目前来说,小程序是不能直接分享到朋友圈的,微信官方只开放了分享到好友和群聊的 API。对于分享到朋友圈,现在大多数小程序所采用的方式,就是根据不同的需求生成一张带小程序码的图片引导用户分享至朋友圈。
当然分享图也可以在后台生成,但是你懂得,基本没有那个后台大哥愿意为你去用代码写一张图出来,所以,咱们还是自给自足,😆。
欢迎大家使用微信扫描【组件库小程序码】(或者微信直接搜索组件库演示
)查看运行效果
生成分享图大致流程如下~
官方文档
关于生成二维码
- 微信官方获取二维码 API
- 如果每一次分享的二维码不同,需要要生成
带参数
的二维码 (采用接口B) - 生成的二维码需要下载到本地
- 别忘了在
小程序微信公众平台后台
-设置
-开发设置
-服务器域名
-downloadFile 合法域名
中添加域名
1. 使用 canvas 进行绘制
我们知道小程序是支持将 canvas 直接转换为图片的,我们可以充分利用这个先决条件
1.1 拿到设计的效果图,我们可以先按标注计算出每个元素的宽高以及在画布中的位置,建议使用 百分比
,这样可以对所有的屏幕大小进行适配
示例代码如下:
const temp = 0.01;
//图片长宽比
const scale = 1.78;
//背景图高度
const bgScale = 0.5;
//头像和宽的比
const avatarWidthScale = 0.368;
const avatarHeightScale = 0.117;
//头像白色圆形背景
const avatarBgWidthScale = 0.38;
const avatarStrokeWidth = 4;
//昵称高度比
const nicknameHeightScale = 0.34 + 5 * temp;
//第一行文字高度
const topTextScale = 0.515 + 3 * temp;
//分享内容
const contentScale = 0.585 + 3 * temp;
const contentScale2 = 0.620 + 3 * temp;
//二维码直径
const qrCodeWidthScale = 0.341;
//二维码高度
const qrCodeHeightScale = 0.69;
//极客文字
const bpbScale = 0.91 + temp * 2;
//识别文字
const decodeScale = 0.935 + temp * 2;
1.2 涉及到图片绘制
- 本地图片可以直接绘制
- 如果要绘制的元素中含有网络图片,需要先将图片下载到本地,不然在真机上无法显示(亲测在模拟器上可以绘制,但在 iPhone6s 真机上无法显示)
- 贴上头像下载代码:
/**
* 下载头像
*/
downloadAvatar: function () {
var that = this;
wx.downloadFile({
url: that.data.avatar,
success: function (res) {
that.setData({
avatarPath: res.tempFilePath
})
that.drawImage();
},
fail: function () {
that.showErrorModel();
}
})
},
1.3 对各个元素进行绘制
- 对于文字过长省略...,目前没有好的办法,暂时采用的是设置最大文字长度,超出截断,并手动添加....
- 对于生成圆形头像,可参考例子实现
drawImage: function () {
var that = this;
const ctx = wx.createCanvasContext('myCanvas', this);
var bgPath = '../../image/share-bg.png';
//设置 canvas 背景,不然生成的图片背景会有黑色底
ctx.setFillStyle(WHITE);
ctx.fillRect(0, 0, windowWidth, windowHeight);
//绘制背景图片
ctx.drawImage(bgPath, 0, 0, windowWidth, windowHeight * bgScale);
//头像背景圆
ctx.arc(windowWidth / 2, avatarWidthScale / 2 * windowWidth + avatarHeightScale * windowHeight, (avatarWidthScale / 2) * windowWidth + avatarStrokeWidth, 0, 2 * Math.PI);
ctx.setFillStyle(WHITE);
ctx.fill();
//先绘制圆,裁剪成圆形图片
ctx.save();
ctx.beginPath();
//圆的原点x坐标,y坐标,半径,起始弧度,终止弧度
ctx.arc(windowWidth / 2, avatarWidthScale / 2 * windowWidth + avatarHeightScale * windowHeight, (avatarWidthScale / 2) * windowWidth, 0, 2 * Math.PI);
ctx.setStrokeStyle(WHITE);
ctx.stroke();
ctx.clip();
//绘制头像
//图片路径,左上角x坐标,左上角y坐标,宽,高
var avatarWidth = avatarWidthScale * windowWidth;//头像半径
ctx.drawImage(that.data.avatarPath, windowWidth * (0.5 - avatarWidthScale / 2), avatarHeightScale * windowHeight, avatarWidth, avatarWidth);
ctx.restore();
//绘制 content
ctx.setFillStyle(GRAY_COLOR);
ctx.setFontSize(18);
ctx.setTextAlign('center');
ctx.fillText(that.data.detailStr.content, windowWidth / 2, contentScale * windowHeight);
ctx.setFillStyle(GRAY_COLOR);
ctx.setFontSize(18);
ctx.setTextAlign('center');
ctx.fillText(that.data.detailStr.contentOther, windowWidth / 2, contentScale2 * windowHeight);
//绘制二维码
ctx.drawImage(that.data.QRPath, windowWidth * (0.5 - qrCodeWidthScale / 2), qrCodeHeightScale * windowHeight, qrCodeWidthScale * windowWidth, qrCodeWidthScale * windowWidth);
console.log('font------------>' + wx.canIUse('canvasContext.font'));
//绘制 按压提示文字
ctx.setFillStyle(TINT_COLOR);
ctx.setFontSize(14);
ctx.setTextAlign('center');
ctx.fillText(that.data.detailStr.clickToMini, windowWidth / 2, decodeScale * windowHeight);
//绘制加粗文字--------------------------------------------------------------
//绘制昵称
that.setFontStyle(ctx, 'bold');
ctx.setFillStyle(WHITE);
ctx.setFontSize(20);
ctx.setTextAlign('center');
ctx.fillText(stringUtil.substringStr(that.data.nickname), windowWidth / 2, nicknameHeightScale * windowHeight);
//绘制文字
ctx.setFillStyle(THEME_COLOR);
ctx.setFontSize(24);
ctx.setTextAlign('center');
ctx.fillText(that.data.detailStr.tip, windowWidth / 2, topTextScale * windowHeight);
//绘制 Geek小程序
ctx.setFillStyle(TINT_COLOR);
ctx.setFontSize(16);
ctx.setTextAlign('center');
ctx.fillText(that.data.detailStr.bpbMini, windowWidth / 2, bpbScale * windowHeight);
//绘制到 canvas 上
ctx.draw(false, function () {
console.log('callback--------------->');
that.saveCanvasImage();
});
}
1.4 兼容处理
- 一些 API 属性是在高版本才有的,比如
文字加粗
(基础库 1.9.90 开始支持,低版本需做兼容处理) - 在使用之前用
wx.canIUse
判断
/**
* 改变字体样式
*/
setFontStyle: function (ctx, fontWeight) {
if (wx.canIUse('canvasContext.font')) {
ctx.font = 'normal ' + fontWeight + ' ' + '14px' + ' sans-serif';
}
},
1.5 不同机型适配
- 可以拿主流的几款手机适配,包括 ios 和 Android,没有问题的话,就可以进行下一步了
2. 调整样式
- 达到效果后修改
wxml
以及wxss
,对 canvas 的样式调整 - 确保 canvas 在屏幕可可显示区域外,因为 canvas 的层级是最高的,我们直接在上面显示图片是不能显示的,也不建议这么做(可以使用
cover-view
) - 这个自由发挥,可以将 canvas 的
position
设置为脱离文档流(fixed
),只要 canvas 不在屏幕显示范围即可,确保离可见区域足够远
.canvas {
width: 100%;
position: fixed;
top: 9999rpx;
left: 0;
}
3. 将 canvas 保存为图片
- 这是最后一步,给用户展示分享图片的同时,用户可以选择保存图片到手机相册
3.1 注意处理用户授权问题
- 同时处理到用户同意和拒绝权限
//转化为图片
saveCanvasImage: function () {
var that = this;
wx.canvasToTempFilePath({
canvasId: 'myCanvas',
success: function (res) {
console.log(res.tempFilePath);
that.setData({
targetSharePath: res.tempFilePath,
realShow: true
})
},
complete: function () {
that.hideLoading();
}
}, this)
},
/**
* 保存到相册
*/
saveImageTap: function () {
var that = this;
that.requestAlbumScope();
},
/**
* 检测相册权限
*/
requestAlbumScope: function () {
var that = this;
// 获取用户信息
wx.getSetting({
success: res => {
if (res.authSetting['scope.writePhotosAlbum']) {
// 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
that.saveImageToPhotosAlbum();
} else {
wx.authorize({
scope: 'scope.writePhotosAlbum',
success(res) {
that.saveImageToPhotosAlbum();
},
fail() {
wx.showModal({
title: '提示',
content: '你需要授权才能保存图片到相册',
success: function (res) {
if (res.confirm) {
wx.openSetting({
success: function (res) {
if (res.authSetting['scope.writePhotosAlbum']) {
that.saveImageToPhotosAlbum();
} else {
console.log('用户未同意获取用户信息权限-------->success');
}
},
fail: function () {
console.log('用户未同意获取用户信息权限-------->fail');
}
})
}
}
})
}
})
}
}
})
},
3.2 保存图片到相册
saveImageToPhotosAlbum: function () {
var that = this;
wx.saveImageToPhotosAlbum({
filePath: that.data.targetSharePath,
success: function () {
wx.showModal({
title: '',
content: '✌️图片保存成功,\n快去分享到朋友圈吧',
showCancel: false
})
that.hideDialog();
}
})
},
- 下面我将讲解小程序自定义组件,以及对保存相册的封装,毕竟分享的地方会很多,封装成组件会大大简化我们的代码量以及工作量,这样就可以少加点班,哈哈
- 简要流程就介绍到这里
- 更多细节参考 Geek 小程序源代码
- 我是源代码,点我,点我,快点我✌️