uniapp 微信小程序自定义分享图片

场景:微信小程序用户,点击小程序里商品的分享按钮时,想要不同的商品展示不用的分享内容,比如分享图片上展示商品的图片、价格等信息。分享的UI图如下: 

 

实现方法:

1. 分享按钮:<button open-type="share">onShareAppMessage(OBJECT)

2. 自定义内容:因为onShareAppMessage的imageUrl参数的支持的是本地文件路径、代码包文件路径或者网络图片路径 ,所以这里实现自定义的分享的方法是结合canvas画布uni.createCanvasContext(canvasId, this),将画好的内容利用uni.canvasToTempFilePath(object, component)导出生成指定大小的图片,再将返回的文件路径赋值给imageUrl,即可实现。

 具体可看官网:分享 | uni-app官网 、uni.createCanvasContext(canvasId, this) | uni-app官网、uni-app官网、uni.canvasToTempFilePath(object, component) | uni-app官网

代码:先贴上画布的代码,这里画了三种自定义分享的内容,样式在代码下方。

1. 新建一个组件文件:ShareCanvas.vue

<template><view class="ShareCanvas"><view class="canvas"><canvas canvas-id="shareCanvas" /></view></view>
</template><script>
export default {name: 'ShareCanvas',methods: {// 订单分享setOrderCanvas(info) {return new Promise(async (resolve, reject) => {console.log('订单分享-info', info);try {const ctx = uni.createCanvasContext('shareCanvas', this)// 绘制背景图ctx.setFillStyle('#19C161')ctx.fillRect(0, 0, 211, 170) // 保证宽高比是 5:4// 绘制文本信息ctx.setFontSize(21);ctx.setTextAlign('left')ctx.setFillStyle('#FFFFFF')ctx.fillText('我买好啦!', 9, 32)// 浅绿色背景this.setRadius(ctx, 10, 106, 11, 97, 27) // 加圆角ctx.setFillStyle('#EFF9F1')ctx.fill()// ctx.fillRect(106, 11, 97, 27) // x, y, width, heightctx.setFontSize(14);ctx.setTextAlign('center')ctx.setFillStyle('#19C161')ctx.fillText('跟团号:' + info.followNum, 155, 30)this.setRadius(ctx, 3, 9, 49, 194, 106)ctx.setFillStyle('#FFFFFF')ctx.fill()// ctx.fillRect(9, 49, 194, 106) // 不设置圆角的时候这么画有背景色的矩形// 画商品图ctx.save();this.setRadius(ctx, 5, 17, 59, 85, 85)ctx.clip();//画了圆 再剪切 原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内try {const { path } = await this.getImge(info.orderCartInfos[0].productImg)ctx.drawImage(path, 17, 59, 85, 85)} catch (error) {console.error(error);}ctx.restore();if (info.teamLeaderUser && info.teamLeaderUser.avatar) {// 团长头像ctx.save();this.setRadius(ctx, 5, 110, 60, 25, 25)ctx.clip(); // 画了圆 再剪切 原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内try {const { path } = await this.getImge(info.teamLeaderUser.avatar)ctx.drawImage(path, 110, 60, 25, 25)} catch (error) {console.error(error);}ctx.restore();}if (info.teamLeaderUser && info.teamLeaderUser.nickname) {// 团长昵称ctx.setFontSize(12);ctx.setTextAlign('left')ctx.setFillStyle('#96999B')ctx.fillText(info.teamLeaderUser.nickname.length > 4 ? info.teamLeaderUser.nickname.slice(0, 4) + '...' : info.teamLeaderUser.nickname, 140, 76)}ctx.setFontSize(14);ctx.setTextAlign('center')ctx.setFillStyle('#FB7415')ctx.fillText(`¥${info.orderCartInfos[0].unitPrice}`, 152, 105)this.setRadius(ctx, 10, 115, 118, 75, 26)const grd = ctx.createLinearGradient(115, 118, 115, 144)grd.addColorStop(0, '#FDAC2F')grd.addColorStop(0.5, '#FDA72C')grd.addColorStop(1, '#FB5615')// 橙色按钮背景ctx.setFillStyle(grd)// ctx.fillRect(230/2, 218/2, 149/2, 53/2) // x, y, width, heightctx.fill()ctx.setFontSize(12);ctx.setTextAlign('center')ctx.setFillStyle('#FFFFFF')ctx.fillText('去看看 >', 152, 135)ctx.draw(false, (() => {setTimeout(() => {uni.canvasToTempFilePath({canvasId: 'shareCanvas',success: (res) => {return resolve(res.tempFilePath)},fail: function (error) {console.log('fail----fail', error);//TODOreturn reject(error)}}, this)}, 500);}))} catch (error) {console.log('画图失败error', error);return reject(error)}})},// 商品分享setGoodsShareCanvas(info) {console.log('商品分享--info', info);return new Promise(async (resolve, reject) => {try {const ctx = uni.createCanvasContext('shareCanvas', this)// 绘制背景图ctx.setFillStyle('#FFFFFF')ctx.fillRect(0, 0, 211, 170)// 团长头像ctx.save();this.setRadius(ctx, 5, 0, 0, 30, 30)ctx.clip(); // 画了圆 再剪切 原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内try {const { path } = await this.getImge(info.avatar)ctx.drawImage(path, 0, 0, 30, 30)} catch (error) {console.error(error);}ctx.restore();// 团长昵称ctx.setFontSize(12);ctx.setTextAlign('left')ctx.setFillStyle('#96999B')ctx.fillText(info.nickname.length > 11 ? info.nickname.slice(0, 11) + `${info.pinkId ? '...的团' : '...'}` : info.nickname + '的团', 35, 18)// 商品1图ctx.save();this.setRadius(ctx, 3, 0, 35, 211, 211)ctx.clip(); // 画了圆 再剪切 原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内try {const { path } = await this.getImge(info.image)ctx.drawImage(path, 0, 35, 211, 211)} catch (error) {console.error(error);}ctx.restore();// 绿色背景ctx.setFillStyle('#19C161')ctx.fillRect(0, 130, 131, 40) // x, y, width, heightctx.setFontSize(16);ctx.setTextAlign('center')ctx.setFillStyle('#FFFFFF')ctx.fillText(`¥${info.pinkId ? info.pinkPrice : info.price}起`, 65, 130 + 18)ctx.setFontSize(12);ctx.setTextAlign('center')ctx.setFillStyle('#FFFFFF')ctx.fillText(`¥${info.otPrice}`, 65, 130 + 34)// 划线ctx.beginPath()ctx.setLineWidth(1);ctx.setStrokeStyle('#FFFFFF')ctx.moveTo(40, 130 + 30)ctx.lineTo(90, 130 + 30)ctx.stroke()// 深绿色背景ctx.setFillStyle('#19AF5C')ctx.fillRect(131, 130, 211 - 131, 40)if (info.pinkId) {// 立即跟团按钮ctx.setFontSize(16);ctx.setTextAlign('center')ctx.setFillStyle('#FFFFFF')ctx.fillText(`立即跟团`, 131 + (211 - 131) / 2, 130 + 26)} else {// 已团数量ctx.setFontSize(12);ctx.setTextAlign('center')ctx.setFillStyle('#FFFFFF')ctx.fillText(`已团 ${this.getSales(info.sales)} 件`, 131 + (211 - 131) / 2, 130 + 25)}ctx.draw(false, (() => {uni.canvasToTempFilePath({canvasId: 'shareCanvas',success: (res) => {return resolve(res.tempFilePath)},fail: function (error) {console.log('fail----fail', error);//TODOreturn reject(error)}}, this)}))} catch (error) {uni.hideLoading()console.log('画图失败error', error);return reject(error)}})},// 团分享setGroupShareCanvas(info) {console.log('团分享-info', info);return new Promise(async (resolve, reject) => {try {const ctx = uni.createCanvasContext('shareCanvas', this)// 绘制背景图ctx.setFillStyle('#FFFFFF')ctx.fillRect(0, 0, 211, 170)if (info.productImageList.length == 1) {// 团长头像ctx.save();this.setRadius(ctx, 5, 0, 0, 30, 30)ctx.clip(); // 画了圆 再剪切 原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内try {const { path } = await this.getImge(info.avatar)ctx.drawImage(path, 0, 0, 30, 30)} catch (error) {console.error(error);}ctx.restore();// 团长昵称ctx.setFontSize(12);ctx.setTextAlign('left')ctx.setFillStyle('#96999B')ctx.fillText((info.nickname.length > 11 ? info.nickname.slice(0, 11) + '...' : info.nickname) + '的团', 35, 18)// 商品1图ctx.save();this.setRadius(ctx, 3, 0, 35, 211, 211)ctx.clip(); // 画了圆 再剪切 原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内try {const { path } = await this.getImge(info.productImageList[0])ctx.drawImage(path, 0, 35, 211, 211)} catch (error) {console.error(error);}ctx.restore();}if (info.productImageList.length >= 2) {// 团长头像ctx.save();this.setRadius(ctx, 5, 0, 0, 42, 42)ctx.clip(); // 画了圆 再剪切 原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内try {const { path } = await this.getImge(info.avatar)ctx.drawImage(path, 0, 0, 42, 42)} catch (error) {console.error(error);}ctx.restore();// 团长昵称ctx.setFontSize(12);ctx.setTextAlign('left')ctx.setFillStyle('#96999B')ctx.fillText((info.nickname.length > 10 ? info.nickname.slice(0, 10) + '...' : info.nickname) + '的团', 47, 25)// 商品1图ctx.save();this.setRadius(ctx, 3, 0, 51, 69, 69)ctx.clip(); // 画了圆 再剪切 原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内try {const { path } = await this.getImge(info.productImageList[0])ctx.drawImage(path, 0, 51, 69, 69)} catch (error) {console.error(error);}ctx.restore();// 商品2图ctx.save();this.setRadius(ctx, 3, 69 + 2, 51, 69, 69)ctx.clip(); // 画了圆 再剪切 原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内try {const { path } = await this.getImge(info.productImageList[1])ctx.drawImage(path, 69 + 2, 51, 69, 69)} catch (error) {console.error(error);}ctx.restore();if (info.productImageList.length >= 3) {// 商品3图ctx.save();this.setRadius(ctx, 3, 69 * 2 + 4, 51, 69, 69)ctx.clip(); // 画了圆 再剪切 原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内try {const { path } = await this.getImge(info.productImageList[2])ctx.drawImage(path, 69 * 2 + 4, 51, 69, 69)} catch (error) {console.error(error);}ctx.restore();}}// 绿色背景ctx.setFillStyle('#19C161')ctx.fillRect(0, 128, 211, 42) // x, y, width, heightctx.setFontSize(16);ctx.setTextAlign('center')ctx.setFillStyle('#FFFFFF')ctx.fillText(`立即跟团`, 211 / 2, 128 + 26)ctx.draw(false, (() => {uni.canvasToTempFilePath({canvasId: 'shareCanvas',success: (res) => {return resolve(res.tempFilePath)},fail: function (error) {console.log('fail----fail', error);//TODOreturn reject(error)}}, this)}))} catch (error) {console.log('画图失败error', error);return reject(error)}})},/*** 设置圆角矩形** @param ctx 绘图上下文* @param cornerRadius 圆角半径* @param width 矩形宽度* @param height 矩形高度* @param x 矩形左上角的 x 坐标* @param y 矩形左上角的 y 坐标* @returns 无返回值*/setRadius(ctx, cornerRadius, x, y, width, height) {// 开始绘制路径ctx.beginPath();// 绘制最左侧的圆角ctx.arc(x + cornerRadius, y + cornerRadius, cornerRadius, Math.PI, Math.PI * 1.5);// 绘制顶部边缘ctx.moveTo(x + cornerRadius, y);ctx.lineTo(x + width - cornerRadius, y);ctx.lineTo(x + width, y + cornerRadius);// 绘制最右侧的圆角ctx.arc(x + width - cornerRadius, y + cornerRadius, cornerRadius, Math.PI * 1.5, Math.PI * 2);// 绘制右侧边缘ctx.lineTo(x + width, y + height - cornerRadius);ctx.lineTo(x + width - cornerRadius, y + height);// 绘制最下侧的圆角ctx.arc(x + width - cornerRadius, y + height - cornerRadius, cornerRadius, 0, Math.PI * 0.5);// 绘制底部边缘ctx.lineTo(x + cornerRadius, y + height);ctx.lineTo(x, y + height - cornerRadius);// 绘制最左侧的圆角ctx.arc(x + cornerRadius, y + height - cornerRadius, cornerRadius, Math.PI * 0.5, Math.PI);// 绘制左侧边缘ctx.lineTo(x, y + cornerRadius);ctx.lineTo(x + cornerRadius, y);// 闭合路径ctx.closePath();},// 获取图片地址getImge(path) {// 利用promise异步转同步,否则可能显示不了~return new Promise((resolve, reject) => {uni.getImageInfo({src: path,success: function (res) {if (res && res.path) {resolve(res)} else {reject(false)}},fail: function (res) {reject(res)}})})},getSales(sales) {return sales >= 10000 ? sales / 10000 + 'w+' : sales},}
}
</script><style lang="scss" scoped>
// 隐藏画布
.ShareCanvas {position: absolute;top: -200px;z-index: -1;opacity: 0;.canvas canvas {width: 211px;height: 170px; // +16}
}
</style>

2. 在分享按钮的页面使用这个画布组件。

onShareAppMessage 方法的内容:

注意:

  1. onShareAppMessage 方法要和 onLoad 等生命周期函数同级
  2. 因为里面画布生成图片是异步的,我在上面用Promise处理了,这里需要async await接收~
async onShareAppMessage(res) {const { id, title, avatar, nickname, productDetailList } = this.detailInfoif (res.target && res.target.id) { // 分享商品console.log('分享商品');const item = productDetailList.find(p => p.id == res.target.id) || {}try {uni.showLoading({ title: '分享信息生成中', mask: true })const imageUrl = await this.$refs.ShareCanvas.setGoodsShareCanvas({ ...item, avatar, nickname, pinkId: id }) // 用不同的画布画样式,就调对应的方法名,注意里面需要的参数要传对uni.hideLoading()return {title: item.storeName || '好物多多,快来选购啦~',path: '/pages/home/index', // 这里是你的分享里面的跳转地址imageUrl: imageUrl || ''}} catch (error) {uni.hideLoading()}} else {// 分享团console.log('分享团', productDetailList);try {uni.showLoading({ title: '分享信息生成中', mask: true })const productImageList = productDetailList.map(item => item.image)const imageUrl = await this.$refs.ShareCanvas.setGroupShareCanvas({ avatar, nickname, productImageList }) // 用不同的画布画样式,就调对应的方法名,注意里面需要的参数要传对uni.hideLoading()return {title: title || '好物多多,快来选购啦~',path: '/pages/home/index', // 这里是你的分享里面的跳转地址imageUrl: imageUrl || ''}} catch (error) {uni.hideLoading()}}},

setOrderCanvas()方法的样式 

 

setGoodsShareCanvas()方法的样式

setGroupShareCanvas()方法的样式

画画的时候,要是找不准xy的位置,可以从这三种样式里选一个样式接近的再慢慢修改~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/30225.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机顶级会议和顶级期刊

顶级会议 国际计算机设计会议&#xff08;ICCD&#xff09;&#xff1a;由国际电气与电子工程师协会&#xff08;IEEE&#xff09;主办&#xff0c;是计算机体系结构领域的国际顶级会议之一&#xff0c;已经成功举办四十余届。 NeurIPS&#xff1a;全称神经信息处理系统大会&a…

电感(线圈)具有哪些基本特性

首先&#xff0c;电感&#xff08;线圈&#xff09;具有以下基本特性&#xff0c;称之为“电感的感性电抗” ?①直流基本上直接流过。 ?②对于交流&#xff0c;起到类似电阻的作用。 ?③频率越高越难通过。 下面是表示电感的频率和阻抗特性的示意图。 在理想电感器中&#…

centos7安装FTP服务器

目录 实验背景 一、配置yum源 1、本地yum 2、阿里云yum 二、安装vsftpd 1、安装vsftp服务 2、启动服务并设置开机自启动 3、开放防火墙和SELinux 三、创建用户和FTP目录 1、创建文件目录并配置权限 2、创建ftp组以及用户 四、修改vsftpd.conf文件 1、备份 vsftpd.c…

C/C++ vector模拟实现

模拟实现&#xff1a; 框架 namespace yx {template<class T>class vector{public:typedef T* iterator;private:iterator _start;iterator _finish;iterator _end_of_storage;}; } 这里我们声明定义不分离 reverse() 新开一个空间&#xff0c;拷贝数据&#xff0c;然…

HTML星空特效

目录 写在前面 完整代码 代码分析 运行效果 系列文章 写在后面 写在前面 100行代码实现HTML星空特效。 完整代码 全部代码如下。 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&g…

【Redis】基于Redission实现分布式锁(代码实现)

目录 基于Redission实现分布式锁解决商品秒杀超卖的场景&#xff1a; 1.引入依赖&#xff1a; 2.加上redis的配置&#xff1a; 3.添加配置类&#xff1a; 4.编写代码实现&#xff1a; 5.模拟服务器分布式集群的情况&#xff1a; 1.右键点击Copy Configuration 2.点击Modi…

怎么投资中证全指证券公司指数?

中证全指证券公司指数的代码是399975&#xff0c;有50只成分股&#xff0c;几乎包含了市场上所有主要的证券公司&#xff0c;算是指数基金中投资证券行业的不二选择。 根据天天基金的数据显示&#xff0c;市面上有31只跟踪该指数的基金&#xff0c;规模最大的是南方中证全指证…

【Java面试】二十二、JVM篇(下):JVM参数调优与排查

文章目录 1、JVM的参数在哪里设置2、常见的JVM调优参数有哪些3、常见的JVM调优工具有哪些4、Java内存泄漏的排查思路5、CPU飙高的排查思路 1、JVM的参数在哪里设置 war包部署&#xff0c;在tomcat中设置&#xff0c;修改TOMCAT_HOME/bin/catalina.sh 文件 jar包启动&#xff0…

jpg格式图片无法打开可以修复吗?有哪些方法?

JPG的图片打不开怎么办呢&#xff1f;当JPG图片打不开的时候&#xff0c;我们需要先了解下具体的原因&#xff0c;是因为格式不支持&#xff0c;还是因为图片文件损坏。不同的原因&#xff0c;解决的方法也会不同&#xff0c;比如图片损坏&#xff0c;我们就需要对图片修复处理…

web爬虫笔记:js逆向案例九(某多多 anti_content参数)补环境流程

web爬虫笔记:js逆向案例九(某多多 anti_content参数)补环境流程 一、目标网站:aHR0cHM6Ly9tb2JpbGUueWFuZ2tlZHVvLmNvbS8= 二、接口分析 1、快速定位加密位置(通过搜索/cells/hub/v3快速定位到加密js文件) 2、通过分析可知&#

双系统下,如何隐藏另一个系统分区?

前言 最近有小伙伴在公众号下留言&#xff1a; 小伙伴说&#xff1a;“双系统时&#xff0c;非当前系统的系统盘能不能屏蔽&#xff1f;&#xff01;比如Win7的系统盘在Win10系统时&#xff0c;盘符成了D盘&#xff0c;安装应用软件时&#xff0c;有些文件就到了D盘&#xff0…

DuDuTalk:智能电子录音工牌在销售场景的应用价值

在快速变化的市场环境中&#xff0c;销售团队面临着日益激烈的竞争和不断变化的客户需求。为了提升销售效率、优化客户体验并加强团队协作&#xff0c;越来越多的企业开始采用智能电子录音工牌作为销售场景中的关键工具。本文将从多个方面探讨智能电子录音工牌在销售场景中的应…

一图读懂腾讯云EdgeOne Open Edge平台

为了鼓励更多开发者参与、共同构建和改进边缘应用&#xff0c;腾讯云EdgeOne面向广大开发者&#xff0c;打造了技术开放共创平台——OpenEdge&#xff0c;该平台是国内首个全免费的边缘应用平台&#xff0c;不仅进一步开放了腾讯云遍布世界各地的边缘节点能力&#xff0c;还可以…

Ollama(docker)+ Open Webui(docker)+Comfyui

Windows 系统可以安装docker desktop 相对比较好用一点&#xff0c;其他的应该也可以 比如rancher desktop podman desktop 安装需要windows WSL 安装ollama docker docker run -d --gpusall -v D:\ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama 这里…

微服务必备容器化技术

文章目录 docker介绍与安装及上手应用什么是容器化技术&#xff1f;为什么需要学习docker&#xff1f;如何理解dockerdocker下载与安装docker的基础组成docker体验 dockerfile介绍并创建go-zero环境容器docker的基础组成从容器构建属于go环境的容器基于dockerfile构建go容器镜像…

最新技术:跨境电商源码,应对多国市场需求,让您轻松开展全球业务!

随着全球化进程的不断推进&#xff0c;跨境电商已成为企业拓展国际市场的重要途径。为了满足不同国家和地区消费者不断增长的需求&#xff0c;跨境电商源码应运而生&#xff0c;为企业提供了便捷高效的全球化业务发展方案。 一、全球化运营的关键 跨境电商源码的核心功能在于…

基本循环神经网络(RNN)

RNN背景&#xff1a;RNN与FNN 在前馈神经网络中&#xff0c;信息的传递是单向的&#xff0c;这种限制虽然使得网络变得更容易学习&#xff0c;但在一定程度上也减弱了神经网络模型的能力。 在生物神经网络中&#xff0c;神经元之间的连接关系要复杂的多。前馈神经网络可以看着…

PySide(PyQt)的特殊按钮(互锁、自锁、独占模式)

界面图: Qt Designer中创建窗口,放置一个QGroupBox,命名为btnStation,这就是自定义的按钮站,按钮站里放置6个按钮。自锁按钮相当于电器中的自锁功能的按钮,每按一次状态反转并保持不变。独占按钮也是自锁功能的按钮,不同的是当独占按钮为ON时,其余所有按钮均被置为OFF…

SmartEDA革新电路设计:告别繁琐,轻松步入智能时代!

在数字化浪潮席卷而来的今天&#xff0c;电路设计的复杂性和繁琐性一直是工程师们面临的难题。然而&#xff0c;随着科技的进步&#xff0c;一款名为SmartEDA的电路设计工具应运而生&#xff0c;它以智能化、高效化的特点&#xff0c;彻底颠覆了传统电路设计的方式&#xff0c;…

在3dmax软件中如何快速创建毛发?---模大狮模型网

在3D建模和渲染中&#xff0c;为角色或物体添加逼真的毛发效果是提升场景真实感的重要步骤之一。然而&#xff0c;手动一根一根创建毛发是非常繁琐的&#xff0c;因此掌握如何在软件中快速生成和调整毛发效果至关重要。模大狮将详细介绍如何利用3ds Max 2018创建毛发&#xff0…