uniapp 使用canvas画海报(微信小程序)

效果展示:

 项目要求:点击分享绘制海报,并实现分享到好友,朋友圈,并保存

先实现绘制海报
 

<view class="data_item" v-for="(item,index) in dataList" :key="index"@click="goDetail(item,index)"><view class="data_bot"><view class="share" @click.stop="goShare(item,index)"><image :src="getimg('share_gray.png')" style="width: 36rpx;height: 36rpx;"></image><view class="share_tt">分享</view></view></view></view><view class="post_box" :class="isShare?' ':'post_box2'"><view class="post"><canvas style="width: 327px; height:482px;margin: 0 auto;" canvas-id="firstCanvas1"></canvas></view></view>
// 生成海报goShare(item, index) {let _this = this;this.shareId = item.idthis.isShare = true// uni.hideTabBar()let userInfo = uni.getStorageSync('userInfo')uni.getImageInfo({src: userInfo.avatar,success: function(res) {if (res.path) {_this.canvasr(item, index, res.path, userInfo.nickname);}},});},
// 画海报canvasr(item, index, avatar, username) {let ctx = uni.createCanvasContext('firstCanvas1');// 背景图let postImage = '../../static/images/poster_bg.png'; //背景图ctx.globalAlpha = 0; // 设置图像透明度为0  为了让背景透明ctx.setFillStyle('#ffffff'); // 默认白色ctx.fillRect(0, 0, 327, 482);ctx.globalAlpha = 1; // 设置图像透明度为1ctx.drawImage(postImage, 0, 0, 327, 482); // (图片,x,y,宽,高)背景图ctx.save();// 头像ctx.restore();// let avatar = userInfo.avatar + "?timestamp=" + Date.now(); //地址栏加入新参数  解决canvas图片跨域问题this.drawAvatar(ctx, avatar, 30, 20, 15)// 昵称 +ctx.setFontSize(12); //设置字体字号ctx.setFillStyle('#000000'); //设置字体颜色// ctx.fillText(username, 65, 39); // (文字,x,y)let _strlineW = 0;let nickname = '';let actI = 0;for (let i = 0; i < username.length; i++) {_strlineW += ctx.measureText(username[i]).width;if(_strlineW <= 60){ctx.fillText(username, 65, 39); // (文字,x,y)}else if (_strlineW > 60 && _strlineW <= 70) {actI = inickname = username.substring(0, i) + '…'ctx.fillText(nickname, 65, 39); // (文字,x,y)}else{nickname = username.substring(0, actI-1) + '…'ctx.fillText(nickname, 65, 39); // (文字,x,y)}}// 分享了一个点子let txt = '我发现了一个不错的点子';ctx.setFontSize(12); //设置字体字号ctx.setFillStyle('#999999'); //设置字体颜色ctx.fillText(txt, 135, 39); // (文字,x,y)// 内容开始引号图let startImage = '../../static/images/poster_quote_up.png'; //背景图ctx.drawImage(startImage, 30, 70, 32, 32); // (图片,x,y,宽,高)背景图ctx.save();ctx.restore();// 内容let content = item.idea_name;this.drawtext(ctx, content, 30, 130, 32, 267)// 内容结束引号图let endImage = '../../static/images/poster_quote_down.png'; //背景图ctx.drawImage(endImage, 265, 310, 32, 32); // (图片,x,y,宽,高)背景图ctx.save();ctx.restore();// 一条直线ctx.setFillStyle('#D8D8D8'); // 默认白色ctx.fillRect(30, 362, 267, 0.5); //x y 宽 高ctx.restore();// logo图let logoImage = '../../static/images/aiyop_logo.png'this.drawAvatar(ctx, logoImage, 30, 402, 15)ctx.save();ctx.restore();// AI有谱let title = 'AI有谱';ctx.setFontSize(13); //设置字体字号ctx.setFillStyle('#000000'); //设置字体颜色ctx.fillText(title, 70, 415); // (文字,x,y)// 心中有谱,奇思妙想也靠谱let intro = '心中有谱,奇思妙想也靠谱';ctx.setFontSize(10); //设置字体字号ctx.setFillStyle('#666666'); //设置字体颜色ctx.fillText(intro, 70, 430); // (文字,x,y)// 二维码let qrImage = '../../static/images/logo_program.jpg';this.drawAvatar(ctx, qrImage, 225, 381, 36)// 绘制ctx.draw();},// 绘制头像drawAvatar(ctx, img, x, y, r) {ctx.save();let d = r * 2;let cx = x + r;let cy = y + r;ctx.beginPath()ctx.arc(cx, cy, r, 0, 2 * Math.PI);ctx.strokeStyle = '#FFFFFF'; // 设置绘制圆形边框的颜色ctx.stroke(); // 绘制出圆形,默认为黑色,可通过 ctx.strokeStyle = '#FFFFFF', 设置想要的颜色ctx.clip();ctx.drawImage(img, x, y, d, d);ctx.restore();},// 文本n行换行与显示省略号// 1、canvas对象 2、文本 3、X轴 4、Y轴 5、单行行高 6、文本的宽度drawtext(ctx, str, axisX, axisY, titleHeight, maxWidth) {ctx.setFontSize(22); //设置字体字号ctx.setFillStyle('#000000'); //设置字体颜色// 文本处理let strArr = str.split("");let row = [];let temp = "";for (let i = 0; i < strArr.length; i++) {if (ctx.measureText(temp).width < maxWidth) {temp += strArr[i];} else {i--; //这里添加了i-- 是为了防止字符丢失,效果图中有对比row.push(temp);temp = "";}}row.push(temp); // row有多少项则就有多少行//如果数组长度大于6,现在只需要显示6行则只截取前两项,把第6行结尾设置成'...'if (row.length > 6) {let rowCut = row.slice(0, 6);let rowPart = rowCut[5];let test = "";let empty = [];for (let i = 0; i < rowPart.length; i++) {if (ctx.measureText(test).width < maxWidth) {test += rowPart[i];} else {break;}}empty.push(test);// let group = empty[0] //这里只显示两行,超出的用...表示let group = empty[0] + "..." //这里只显示两行,超出的用...表示rowCut.splice(5, 1, group);row = rowCut;}// 把文本绘制到画布中for (let i = 0; i < row.length; i++) {// 一次渲染一行ctx.fillText(row[i], axisX, axisY + i * titleHeight, maxWidth);}// 保存当前画布状态ctx.save()// 将之前在绘图上下文中的描述(路径、变形、样式)画到 canvas 中。// ctx.draw()},

下面是海报下面的分享弹窗

<!-- 分享海报的遮罩层 --><view v-if="isShare" class="over_box" @touchmove.stop.prevent="moveHandle"></view><!-- 分享海报 --><u-popup :show="isShare" @close="closeShare" @open="openShare" mode="bottom" :round="10" :overlay="false"><view class="trans_box"><view class="per_box"><button open-type="share" class="per_but" @click="shareWeixin('WXSceneSession')"><image :src="getimg('wehcat.png')" style="width:86rpx;height: 86rpx;"></image><view class="per_txt">微信好友</view></button><button class="per_but" @click="shareWeixin('WXSceneTimeline')"><image :src="getimg('wechat-moments.png')" style="width:86rpx;height: 86rpx;"></image><view class="per_txt">朋友圈</view></button><button @click="saveLocal" class="per_but"><image :src="getimg('save-poster.png')" style="width:86rpx;height: 86rpx;"></image><view class="per_txt">保存图片</view></button></view><view class="share_line"></view><view class="close_tran" @click="closeShare">取消</view></view></u-popup>

因为分享到朋友圈实在没找到有使用自定义按钮的可能,所以还是需要点击右上角胶囊
 

onLoad(){//分享功能wx.showShareMenu({withShareTicket: true,//设置下方的Menus菜单,才能够让发送给朋友与分享到朋友圈两个按钮可以点击menus: ["shareAppMessage", "shareTimeline"]})}
//点击分享朋友,朋友圈事件
shareWeixin(scene) {if (scene == 'WXSceneTimeline') {uni.showToast({title: '点击右上角胶囊分享朋友圈',icon: 'none',duration: 2000})} else {uni.share({provider: "weixin",scene: scene,type: 0,href: '/subPackage/index/like_details?id=' + this.shareId + '&type=1',title: '点子分享',success(res) {console.log(res);},fail(err) {console.log(err);}})}},
onShareAppMessage(res) {if (res.from === 'button') { // 来自页面内分享按钮return {title: 'xxxxxxx', //分享的名称path: '/subPackage/index/like_details?id=' + this.shareId + '&type=1',mpId: 'wx000000000', //此处配置微信小程序的AppIdimageUrl: ''}}return {title: 'xxxxx', //分享的名称path: '/subPackage/index/like_details?id=' + this.shareId + '&type=1',mpId: 'wx0000000000', //此处配置微信小程序的AppIdimageUrl: ''}},//分享到朋友圈onShareTimeline(res) {return {title: this.timeItem,path: '/pages/index/index',type: 0,summary: "",imageUrl: ''}},

 以上就是画海报以及分享的全部过程了,另有一个点:
就是分享朋友的地址path: '/subPackage/index/like_details?id=' + this.shareId + '&type=1'
这里这个加个type=1是因为点击分享进入小程序的是个详情页,可能会出现点击左上角返回不能返回首页,所以加上这个type可以在分享页加个判断
 

        onLoad(option) {if(option.type && option.type==1){ //分享来的页面this.shareType = 1}},
//左上角的点击返回事件加判断,当是分享进入的时候回到首页goBack(){if(this.shareType==1){uni.switchTab({url:'/pages/index/index'})}else{uni.navigateBack()this.shareType = 0}},

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

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

相关文章

【OpenVINOSharp】 基于C#和OpenVINO2023.0部署Yolov8全系列模型

基于C#和OpenVINO2023.0部署Yolov8全系列模型 1 项目简介1.1 OpenVINOTM 2 OpenVinoSharp2.1 OpenVINOTM 2023.0安装配置2.2 C 动态链接库2.3 C#构建Core推理类2.4 NuGet安装OpenVinoSharp 3 获取和转换Yolov8模型3.1 安装ultralytics3.2 导出yolov8模型3.3 安装OpenVINOTM Pyt…

ssm学院党员管理系统源码和论文PPT

ssm学院党员管理系统源码和论文PPT002 开发工具&#xff1a;idea 数据库mysql5.7(mysql5.7最佳) 数据库链接工具&#xff1a;navcat,小海豚等 开发技术&#xff1a;java ssm tomcat8.5 选题意义、价值和目标&#xff1a; 随着鄂尔多斯应用技术学院招生规模的不断扩大&…

LeetCode209. 长度最小的子数组

题目&#xff1a;LeetCode209. 长度最小的子数组 描述&#xff1a; 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl1, …, numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条件的子…

改进DevSecOps框架的 5 大关键技术

Markets and Markets的一项研究显示&#xff0c;全球DevOps的市场规模从2017年的29亿美元增加到2023年的103.1亿美元&#xff0c;预测期的年复合增长率(CAGR)为24.7%。人们对DevOps越来越感兴趣&#xff0c;因为DevOps不仅能够压缩软件的交付周期&#xff0c;还能提高交付的速度…

geeemap学习总结(1)——Anaconda-VSCode-geemap环境安装与配置

配置conda geemap 环境 通过Anaconda配置geemap环境较为方便&#xff0c;首先需在系统中完成 Anaconda安装。创建名为geemap的环境conda create -n geemap切换到新建的环境conda activate geemap安装geemap依赖包conda install -c conda-forge geemap 安装mambaconda install …

ACM算法竞赛中在编辑器中使用输入输出样例-CPH

通用方法 我们可以在编辑器中创建三个文件&#xff0c;一个是main.cpp,一个是test.in,一个是test.out分别用来写代码&#xff0c;输入输入数据&#xff0c;显示输出数据 这种方法的好处是不需要插件&#xff0c;在任何编辑器中都可以实现&#xff0c;例如Devc,sublime,vscode…

【Pyhthon实战】Python对全校电费查询采集并可视化分析

前言 今天,我来说说怎么抓取宿舍电费的过程。我们学校是在完美校园交电费的,我们可以不用取抓包完美校园的数据接口,我们可以直接登录学校的一卡通网站,每个学校都有,大家可以自己找找,这里我为什么要抓包呢,因为学校提供的网站已经打不开了,这里就不介绍怎么抓包了。 …

直播电商赋能跨境业务,Live Market创造全民参与的生态圈

全球疫情的影响让跨境电商业务受到了巨大的冲击&#xff0c;但同时也为跨境电商业务带来了新的机遇和挑战。直播电商作为电子商务行业的新兴业务版块&#xff0c;成为了跨境电商业务的一个重要推动力量。在这个背景下&#xff0c;直播电商成为了跨境电商业务的一个主流业务版块…

php-cgi.exe - FastCGI 进程超过了配置的请求超时时限

解决方案一&#xff1a; 处理(php-cgi.exe - FastCGI 进程超过了配置的请求超时时限)的问题 内容转载&#xff1a; 处理(php-cgi.exe - FastCGI 进程超过了配置的请求超时时限)的问题_php技巧_脚本之家 【详细错误】&#xff1a; HTTP 错误 500.0 - Internal Server Error C:…

python爬虫之scrapy框架介绍

一、Scrapy框架简介 Scrapy 是一个开源的 Python 库和框架&#xff0c;用于从网站上提取数据。它为自从网站爬取数据而设计&#xff0c;也可以用于数据挖掘和信息处理。Scrapy 可以从互联网上自动爬取数据&#xff0c;并将其存储在本地或在 Internet 上进行处理。Scrapy 的目标…

vue3中用watch监听响应式数据的注意点

如果你在vue3中使用reactive()方法创建响应式数据&#xff0c;然后又用torefs()方法将响应式数据解构成单一的ref响应式数据。 此时&#xff0c;如果你想用watch监听解构出来单一的响应式数据&#xff0c;watch不起作用。 此时&#xff0c;你需要用watch监听之前的reactive()…

Python如何打开pkl的sample text?(上篇)

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 昨夜闲潭梦落花&#xff0c;可怜春半不还家。 大家好&#xff0c;我是皮皮。 一、前言 前几天在Python私教群【Emma】问了一个Python读取数据的问题&am…

mysql_docker主从复制_实战_binlog混合模式_天座著

步骤1&#xff1a;拉取镜像 docker pull mariadb:latest 步骤2.1&#xff1a;创建两个文件夹用于放置挂载mysql的my.cnf /tianzuomysqlconf/master /tianzuomysqlconf/slave mkdir /tianzuomysqlconf cd /tianzuomysqlconf mkdir master mkdir slave 步骤2.2&#xff1a;创…

ElasticSearch:全文检索及倒排索引原理

1.从全文检索说起 首先介绍一下结构化与非结构化数据&#xff1a; 结构化数据将数据具有的特征事先以结构化的形式定义好&#xff0c;数据有固定的格式或有限的长度。典型的结构化数据就是传统关系型数据库的表结构&#xff0c;数据特征直接体现在表结构的字段上&#xff0c;…

idea数据库快速上手-库操作与表结构和数据操作

引言 对数据库的操作无非就是执行SQL语句&#xff0c;要想熟练操作数据库&#xff0c;就要熟练运用SQL语句。 一&#xff0c;数据库操作 展示当前服务器内的数据库 -- 展示服务器内的数据库 show databases; show schemas; 执行结果&#xff1a; 创建数据库&#xff1a; --…

云技术-混沌工程

目录 混沌工程 故障注入 监控和观测 自动化和持续集成 混沌工程 混沌工程&#xff08;Chaos Engineering&#xff09;是一种实验性的系统可靠性工程方法&#xff0c;主动引入故障和异常来测试系统的弹性和容错能力。混沌工程的核心思想是通过模拟故障场景来验证系统在各种异…

springboot项目打包 以及打包碰到各种问题

PS:以上资料都来自于网络 1.IDEA 将springboot项目打包 IDEA如何打包springboot成jar包&#xff0c;并运行、停止、重启&#xff0c;本地依赖不能打包怎么办_真是6的不行的博客-CSDN博客 2.[WARNING] Error injecting: org.springframework.boot.maven.RepackageMojo 1.注释…

Python中搭建IP代理池的妙招

在Python的爬虫世界里&#xff0c;你是否也想搭建一个功能强大的IP代理池&#xff0c;让你的爬虫无忧无虑地畅游各大网站&#xff1f;今天&#xff0c;我就来教你使用Scrapy框架搭建IP代理池&#xff0c;让你的爬虫更加智能、高效&#xff01;跟着我一步一步来&#xff0c;轻松…

Pytorch基于VGG cosine similarity实现简单的以图搜图(图像检索)

代码如下&#xff1a; from PIL import Image from torchvision import transforms import os import torch import torchvision import torch.nn.functional as Fclass VGGSim(torch.nn.Module):def __init__(self):super(VGGSim, self).__init__()blocks []blocks.append(t…

使用乐观锁解决超卖问题

目录 什么是超卖&#xff1f; 乐观锁和悲观锁的定义 悲观锁&#xff1a; 乐观锁&#xff1a; 乐观锁的实现方式 1.版本号 2.CAS法 什么是超卖&#xff1f; 举个例子&#xff1a;订单系统中&#xff0c;用户在执行下单操作时&#xff0c;可能同一时间有无数个用户同时下单&…