如何在小程序端生成分享海报

最近更新时间:2024-04-15 14:40:51

我的收藏

使用场景

在小程序的一些应用场景中,需要实现在线生成分享海报的功能,方便用户进行多渠道的转发。本篇实践案例就是基于此类场景,讲解如何利用微搭平台实现小程序端生成分享海报的功能。

实现方案

利用编辑器 Canvas 组件生成画布实例、自定义 Js 方法完成绘画、小程序 API(wx.canvasToTempFilePath)将画布导出为图片、编辑器弹窗组件展示图片以及小程序 API(wx.saveImageToPhotosAlbum)实现保存图片。

步骤1: 准备工作

素材图片:
此次实践准备了两张图片,分别是海报模板和二维码,海报模板用作画布的底图,二维码绘制到画布的右下角(图片可根据需求自行设计),两张图片需要上传到微搭素材库,图片链接可单击图片右下方图标进行复制。



微搭平台授权认证的小程序:
由于生成分享海报功能涉及到小程序 API(wx.系列方法),编辑器下的预览模式无法调用其相关方法,所以在应用发布的时候需要绑定小程序,才能在终端预览真机效果,若之前没有注册过小程序,请在微搭控制台按照指引进行小程序注册、授权认证即可。




步骤2: 场景搭建

在编辑器窗口新建按钮组件弹窗组件以及 Canvas 组件,实现单击下载海报按钮,出现海报弹窗,单击弹窗底部保存到相册按钮,即可保存图片到相册的场景。
说明:
因小程序在编辑器模式(预览模式)和真机模式下,实现场景效果代码方法有所区别,下文将以真机环境下的运行实例进行效果演示,涉及代码片段为生产环境的正式方法。
下载海报按钮:绑定点击事件,执行方法选择组件弹窗。



海报展示弹窗:按下图方式进行配置。
弹窗大纲树结构。



弹窗底部按钮相关设置。



Canvas 组件:放入弹窗容器中,清除初始化代码宽度设为100%,在渲染完成 canvasReady 事件绑定自定义 JS 方法。



为了更加接近真实场景,在调用上述方法 JS 方法的时候,我们传递三个参数,分别是用户昵称、头像、分享标语(具体传参方式可根据实际场景进行选择)。
说明:
编辑器预览模式下可调用系统方法 $w.auth.currentUser 获取当前用户信息。
真机预览模式 PC/H5 请先配置访问控制PC/H5 端登录配置方法),才可以使用 $w.auth.currentUser 方法获取用户头像、昵称。
真机模式小程序请使用小程序 开放接口|用户信息 获取用户微信昵称、头像(若在用户刚打开小程序时就要求收集用户的微信昵称、头像,或者在支付前等不合理路径上要求授权。如果用户拒绝授权,则无法使用小程序或相关功能)。




步骤3: 生成海报

Canvas 渲染完成,触发自定义 JS 方法,完成画布绘画并生成图片,自定义 JS 方法核心代码如下:
export default async function ({ event, data }) {
/**
* canvas相关参数介绍:
* $w.组件id.canvasInstance(Weda内置方法): 获取canvas实例
* $w.组件id.canvasCtx(Weda内置方法): 获取canvas上下文
* clearRect:清除指定的矩形区域,然后这块区域会变得透明
* fillRect:绘制一个填充的矩形
* fillStyle:填充字体的颜色
* fillText:在指定的(x,y)位置填充指定的文本
* drawImage:图片基本绘制方法
* 更多请参考微搭Canvas组件:https://docs.cloudbase.net/lowcode/components/wedaUI/src/docs/compsdocs/show/WdCanvas
* 海报绘制完成之前 ,设置一个loading状态提示 微搭内置交互方法:$w.utils.showLoading
*/
$w.utils.showLoading({
title: "加载中",
mask: false,
})
//获取canvas实例和上下文
const canvas = $w.canvas2.canvasInstance
const ctx = $w.canvas2.canvasCtx
//获取可视窗口的宽高
const width = $w.device.viewport.width
const height = $w.device.viewport.height
//获取设备像素比
let dpr = wx.getWindowInfo().pixelRatio
if (ctx && canvas && $w.canvas2?.type === '2d') {
// 清空画布
ctx.clearRect(0, 0, width, height)
//初始化画布大小、画布的最终大小需要按设备像素比进行转换、
canvas.width = width * dpr
canvas.height = height * dpr
ctx.scale(dpr, dpr)
//ctx.fillStyle = "rgb(246, 248, 251,0)";
//ctx.fillRect(0, 0, canvas.width, canvas.height)
//准备好的poster图片和二维码图片
let posterMoudleImg = 'https://lowcode-0ghsfkoo8e3f415d-1258057692.tcloudbaseapp.com/resources/2024-01/lowcode-1579027'
let codeImg = 'https://lowcode-0ghsfkoo8e3f415d-1258057692.tcloudbaseapp.com/resources/2024-01/lowcode-1576045'
//获取海报图片的尺寸
let posterImgInfo = await new Promise((reslove) => {
wx.getImageInfo({
src: posterMoudleImg,
success(res) {
reslove(res);
}
})
})
// 计算出新的图片宽高(此处以宽为基准,按90%的宽等比例缩放图片)
let posterImgRate = posterImgInfo.width / posterImgInfo.height
let posterWidth = 0.9 * width
let posterHeight = posterWidth / posterImgRate
//获取poster图片信息
let posterImg = canvas.createImage()
posterImg.src = posterMoudleImg
posterImg.onload = async () => {
//绘制海报底图
let x_position = (width - posterWidth) / 2, y_position = 20
ctx.drawImage(posterImg, x_position, y_position, posterWidth, posterHeight)
// 绘制用户头像
const avatImg = canvas.createImage()
avatImg.src = data.target.avataurl
avatImg.onload = async () => {
//let y4 = y3 + 20
ctx.drawImage(avatImg, x_position + 40, posterHeight / 2, 60, 60)
}
//绘制用户昵称
let nickName = "用户ID:" + data.target.nickname;
ctx.font = "16px bold";
ctx.fillStyle = "white"
ctx.fillText(nickName, x_position + 110, posterHeight / 2 + 40);
//绘制分享语
let shareWords = '"' + data.target.shareWords + '"';
ctx.font = "18px bold";
ctx.fillStyle = "white"
ctx.fillText(shareWords, x_position + 40, posterHeight / 2 + 100);
// 绘制小程序码
const qrcodeImg = canvas.createImage()
qrcodeImg.src = codeImg
qrcodeImg.onload = async () => {
ctx.drawImage(qrcodeImg, 0.75 * posterWidth, 0.83 * posterHeight, posterWidth / 4, posterWidth / 4)
}
/**
* 把当前画布指定区域的内容导出生成指定大小的图片。在 draw() 回调里调用该方法才能保证图片导出成功。暂不支持离屏 canvas。
* 更多请参考小程序wx.canvasToTempFilePath方法:https://developers.weixin.qq.com/miniprogram/dev/api/canvas/wx.canvasToTempFilePath.html
* success回调参数res.tempFilePath; tempFilePath:图片临时路径
* 微搭内置方法:运行终端类型$w.wedaContext.platforms
* 微搭内置方法:设置变量tempFilePath并赋值,$w.page.setState({"tempFilePath": res.tempFilePath})
*/
if ($w.wedaContext.platforms.includes('MP')) {
setTimeout(() => {
ctx.draw(true, wx.canvasToTempFilePath(
{
x: x_position, // 指定的画布区域的左上角横坐标
y: y_position, // 指定的画布区域的左上角纵坐标
width: width - x_position * dpr * 2, // 指定的画布区域的宽度
height: (width - x_position * dpr * 2) / posterImgRate, // 指定的画布区域的高度
destWidth: (width - x_position * dpr * 2) * dpr, // 输出的图片的宽度
destHeight: (width - x_position * dpr * 2) / posterImgRate * dpr, // 输出的图片的高度
canvas: canvas,
//quality: 1,
success(res) {
$w.page.setState({ "tempFilePath": res.tempFilePath }) //将图片临时路径保存到自定义变量tempFilePath
//console.log($w.page.dataset.state.tempFilePath)
},
fail(res) {
console.log('error')
$w.utils.showToast({
title: "保存失败", // 提示的内容,
icon: "error", // 图标,
duration: 2000, // 延迟时间,
mask: true, // 移动端是否显示透明蒙层(移动端显示透明蒙层可以防止触摸穿透,PC 端不受此配置影响)
})
},
complete(res) {
//console.log(res)
$w.utils.hideLoading();
}
})
)
}, 1500)
}
}
}
}
说明:
上述代码为真机模式(生产环境)下的代码,可根据实际需求进行调整,代码片段中涉及重点相关参数、方法、API,如下:
方法
作用
来源
备注
$w.组件id.canvasInstance
获取 Canvas实例
微搭内置方法
$w.组件id.canvasCtx
获取 Canvas 上下文
微搭内置方法
$w.device
获取设备信息
微搭内置方法
$w.wedaContext.platforms
获取终端类型
微搭内置方法
wx.getWindowInfo().pixelRatio
获取设备像素比
小程序 API 接口
Canvas.createImage()
创建图片对象
小程序 API 接口
CanvasContext.drawImage()
绘制图像到画布
小程序 API 接口
wx.canvasToTempFilePath()
将画布导出为图片
小程序 API 接口
弹窗组件底部按钮绑定点击事件并调用自定义 JS 方法,实现保存图片,自定义 JS 方法核心代码如下:
export default function savePoster() {
wx.saveImageToPhotosAlbum({
filePath: $w.page.dataset.state.tempFilePath, //图片临时路径
success(res) {
$w.utils.showToast({
title: "保存成功", // 提示的内容,
icon: "success", // 图标,
duration: 2000, // 延迟时间,
mask: true, // 移动端是否显示透明蒙层(移动端显示透明蒙层可以防止触摸穿透,PC 端不受此配置影响)
});
},
fail(res) {
$w.utils.showToast({
title: "保存失败", // 提示的内容,
icon: "error", // 图标,
duration: 2000, // 延迟时间,
mask: true, // 移动端是否显示透明蒙层(移动端显示透明蒙层可以防止触摸穿透,PC 端不受此配置影响)
});
}
})
}
说明:
小程序 APIwx.saveImageToPhotosAlbum() 保存图片到系统相册,具体请参见 小程序官方文档

步骤4: 发布应用、真机效果展示

发布应用时请关联已在微搭平台内认证的小程序



发布成功扫码进入小程序,单击下载海报(小程序真机模式) > 生成海报 > 单击保存到相册 > 保存成功,下面展示的是真机运行效果。







场景应用

小程序分享朋友圈的是“单页模板”的方式,关于相关限制可以参考小程序 开放能力 /分享到朋友圈,因此在小程序的实际分享朋友圈的场景中,大多是采用分享海报或者小程序码的形式,由于上述方式中已经讲述了如何生成分享海报的功能,所以只要用实际场景中的小程序码替换掉海报中的二维码,即可复现真实场景的分享功能,小程序码的获取方法:
1. 微信公众平台下载。



2. 应用发布成功之后,在编辑器左侧单击应用设置图标,在应用详情中可以查看应用到小程序码,鼠标右键即可保存图片到本地。




注意事项

注意:
编辑器模式下无法调用小程序相关 API,因此想要在编辑器中预览效果,上述代码需要作出相应调整,涉及到设备分辨率、图片信息、用户信息等获取方式的调整。
可根据实际需求进行相应绘画参数的调整,从而达到理想的海报布局效果。
绘制元素过多的时候,由于 ctx.draw() 是异步方法,请使用 setTimeout() 方法延迟触发,防止导出图片空白问题。
若要生成动态二维码,可利用微搭二维码组件,具体请参见 二维码组件使用指引

其它说明

微信小程序分享朋友圈目前遵循“单页模式”机制:
要求分享的页面里不涉及登录、鉴权、交互等功能,只适合纯内容展示的分享场景。
不允许跳转到其它页面,包括任何跳小程序页面、跳其它小程序、跳微信原生页面。
目前微搭上搭建的小程序涉及到鉴权操作,无法满足微信小程序分享朋友圈的相关要求。
大部分分享朋友圈一般采取的是分享小程序码或者海报的方式,更多请参见 小程序分享朋友圈 相关说明。