当前位置: 首页 > news >正文

Uniapp 微信小程序分享 - 自定义绘制分享图片

技术栈: Uniapp + Vue3

简介

因实际业务需求,需要实现微信小程序自定义分享,根据当前数据动态生成(绘制)分享卡片的图片。
基础分享使用 配置此处不在赘述,可查看上篇博客:Uniapp 微信小程序分享 - 自定义卡片内容 + 参数携带 接收
为了实现绘制分享卡片,核心需要使用 uni.createCanvasContext
先来看一下效果:
绘制分享卡片

中间的图片绘制分四个部分:

  1. 卡片背景图(带小程序名称的红色边框和“马上抢”)
  2. 用户头像
  3. 店铺图片
  4. 其余文字

注意:绘制图片必须需要专门使用uni.getImageInfo获取图片的path后,再使用canvas.drawImage绘制,否则直接用图片路径绘制不成功,会成默认的分享图。

实现

DOM

需要

  1. 在DOM上创建canvas元素
  2. 设置 canvas-id和画布大小
  3. 设置样式让画布不在可视区域内。
<template>
<button open-type="share" class="share-btn">分享</button>
<canvas canvas-id="hoCanvas" style="width: 300px;height: 240px;position: fixed; right: -999999999rpx;"></canvas>
<template>

onShareAppMessage事件

因为获取路片路径、canvas画图会比较慢,可提前加载好固定的图片素材。

import { ref, getCurrentInstance } from 'vue'
import { getImgPath, savePoster } from './utils.js'
import { onLoad, onShareAppMessage } from '@dcloudio/uni-app';const that = getCurrentInstance();const shareImg = ref();const info = ref({shopName: '店铺名'logoUrl: 'https://p1.meituan.net/business/a199b07951349e881d3a38b9f28b832d458281.png',nickName: '7788',price: 10,num: 100,avatar: '',shareBg: ''});// 绘制分享卡片
const initShareImg = () => {savePoster(info.value, (res) => {shareImg.value = res;})
}// 页面加载就开始绘制卡片
onLoad(() => {//	获取卡片背景pathgetImgPath('https://zj-biz-gov-free-eat.oss-cn-hangzhou.aliyuncs.com/free-eat/static-example/share-activity.png', '店铺分享卡片背景',(res) => {info.value.shareBg = res;
});// 获取头像pathgetImgPath('https://zj-biz-gov-free-eat.oss-cn-hangzhou.aliyuncs.com/free-eat/user/oR1KL7S9-m6ryWDar-1h_vaCOPXw/18860235410318-1731415218.jpg', '用户头像', (res) => {info.value.avatar = res;});// 背景图 头像路径获取完了再绘制分享图setTimeout(() => {initShareImg();},2000)})// 分享活动
onShareAppMessage((res) =>{that.proxy.mpShare.title =  `${info.value.shopName}】开抢啦!限量${info.value.num}份,最高返${info.value.price}元!`;that.proxy.mpShare.path = `/pages/orderPage/joinDetailMt/indexNew`;// 绘制失败则使用微信默认的快照图片if (shareImg.value) that.proxy.mpShare.imageUrl = shareImg.value;
});

utils 工具函数


export const fillRoundRect = (ctx, x, y, width, height, radius, img) => {// console.log(ctx, x, y, width, height, radius, /*optional*/ fillColor)ctx.save();ctx.translate(x, y);//绘制圆角矩形的各个边drawRoundRectPath(ctx, width, height, radius);ctx.clip();ctx.drawImage(img, 0, 0, width, height);// ctx.fillStyle = fillColor || "blue"; //若是给定了值就用给定的值否则给予默认值// ctx.fill();ctx.restore();
};export const drawRoundRectPath = (ctx, width, height, radius) => {ctx.beginPath(0);//从右下角顺时针绘制,弧度从0到1/2PIctx.arc(width - radius, height - radius, radius, 0, Math.PI / 2);//矩形下边线ctx.lineTo(radius, height);//左下角圆弧,弧度从1/2PI到PIctx.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);//矩形左边线ctx.lineTo(0, radius);//左上角圆弧,弧度从PI到3/2PIctx.arc(radius, radius, radius, Math.PI, Math.PI * 3 / 2);//上边线ctx.lineTo(width - radius, 0);//右上角圆弧ctx.arc(width - radius, radius, radius, Math.PI * 3 / 2, Math.PI * 2);//右边线ctx.lineTo(width, height - radius);ctx.closePath();
}// 分享卡片绘制
export const savePoster = (info, callback) => {const { logoUrl, nickName, price, num, shareBg, avatar } = info;const canvas = uni.createCanvasContext('hoCanvas');uni.getImageInfo({src: logoUrl,success: (logoRes) => {canvas.drawImage(shareBg, 0, 0, 300, 240);fillRoundRect(canvas, 10, 37, 160, 160, 10, logoRes.path);canvas.setFontSize(12);canvas.setFillStyle("#333");// canvas.setStrokeStyle('#333');canvas.fillText('最高返', 180, 88);canvas.setFontSize(12);canvas.setFillStyle("#FD3540");canvas.setStrokeStyle('#FD3540');canvas.fillText('¥', 216, 88);canvas.setFontSize(24);canvas.setFillStyle("#FD3540");canvas.setStrokeStyle('#FD3540');canvas.fillText(price, 225, 88);canvas.setFontSize(16);canvas.setFillStyle("#3D3D3D");canvas.setStrokeStyle('#3D3D3D');canvas.fillText('霸王餐', 174, 110);canvas.setFontSize(16);canvas.setFillStyle("#FD3540");canvas.setStrokeStyle('#FD3540');canvas.fillText(`限量${num}份!`, 222, 110);fillRoundRect(canvas, 4, 210, 22, 22, 11, avatar);canvas.setFontSize(12);canvas.setFillStyle("#FFFFFF");canvas.setStrokeStyle('#FFFFFF');canvas.fillText(`${nickName}为您推荐`, 30, 225);canvas.draw(false, () => {// 获取 canvas 的临时路径uni.canvasToTempFilePath({canvasId: 'hoCanvas',success: (tempFilePathRes) => {const tempFilePath = tempFilePathRes.tempFilePath;callback(tempFilePath);console.log('临时路径:', tempFilePath);},fail: (err) => {console.error('获取临时路径失败:', err);}});});},fail: (err) => {console.error('获取分享图片信息失败:', err);message(`获取店铺图片信息失败,请稍后重试`)}});
}// 获取图片path【店铺分享背景、用户头像】
export const getImgPath = (img, name, callback) => {uni.getImageInfo({src: img,success: (imgRes) => {callback(imgRes.path);},fail: (err) => {console.error(`获取${name}图片信息失败,请稍后重试`, err);}})
}
http://www.lryc.cn/news/497315.html

相关文章:

  • 鸿蒙技术分享:Navigation页面容器封装-鸿蒙@fw/router框架源码解析(三)
  • 三步入门Log4J 的使用
  • VBA中类的解读及应用第十八讲:利用类方法,判断任意单元格类型
  • 查询品牌涉及两张表(brand、brand_admin_mapping)
  • Eureka和Zookeeper、Nacos的区别
  • 微信小程序怎么实现非tabbar页面显示tabbar,自定义组件实现
  • SpringBoot如何使用EasyExcel实现表格导出(简洁快速入门版本)
  • 多种平台上安装部署调试Open5GS(四)
  • 单片机的基本构成与工作原理
  • opencv常用图像处理操作
  • Svn如何切换删除账号
  • 使用PaddleOCR遇到的问题Bug
  • 了解Xcode在iOS开发中的作用和功能有哪些
  • 《船舶物资与市场》是什么级别的期刊?是正规期刊吗?能评职称吗?
  • 商汤完成组织架构调整,改革完成的商汤未来何在?
  • MyBatis异常体系中ErrorContext和ExceptionFactory原理分析
  • WHLUG丨deepin、华中科技大学开放原子开源俱乐部、 RustSBI 和清华大学开源操作系统训练营共话开源新生代成长之路
  • 通过HTML Canvas 在图片上绘制文字
  • C# 冒泡的算法
  • 大数据项目-Django基于聚类算法实现的房屋售房数据分析及可视化系统
  • AWS创建ec2实例并连接成功
  • TypeScript 开始学习 -接触的新东西
  • 非对称任意进制转换器(安卓)
  • 【优选算法篇】寻找隐藏的宝藏:用二分查找打开算法世界的大门(上篇)
  • 基于Vue实现的移动端手机商城项目 电商购物网站 成品源码
  • C语言:数组
  • 时间序列预测之FiLM
  • 【机器学习】窥数据之序,悟算法之道:机器学习的初心与远方
  • OpenCL介绍
  • 「Mac畅玩鸿蒙与硬件42」UI互动应用篇19 - 数字键盘应用