uniapp如何使用canvas绘制海报,自适应屏幕尺寸,并且下载本地?

news2025/2/21 22:56:26

组件目录 /share-canvas.vue

<template>
	<u-popup :show="visiable" closeable @close="hiddenCanvas" zIndex="999999">
		<view class="shareModel" @touchstart="" @touchmove="" @touchend="">
			<view class="title">分享店铺</view>
			<template v-if="visiable">
				<canvas canvas-id="posterid" :style="{width:screen_width*375+'px',height:screen_height*0.65+'px'}"
					class="myCanvas" disable-scroll="true" @touchstart="" @touchmove="" @touchend=""></canvas>
			</template>
			<view class="share-bot" @click.stop>
				<view class="share-btns">
					<!-- <view class="btns-list" @click="handleCopyLink">
						<u--image :showLoading="true" :src="copyLink" width="72rpx" height="72rpx" />
						<text>复制链接</text>
					</view> -->
					<view class="btns-list">
						<button class="btns-box" open-type="share">
							<u--image :showLoading="true" :src="copyLink" width="72rpx" height="72rpx" />
							<text>分享链接</text>
						</button>
					</view>
					<view class="btns-list" @click="savePoster(100)">
						<u--image :showLoading="true" :src="saveIcon" width="72rpx" height="72rpx" />
						<text>保存二维码</text>
					</view>
					<view class="btns-list" @click="savePoster(200)">
						<u--image :showLoading="true" :src="saveIcon" width="72rpx" height="72rpx" />
						<text>保存海报</text>
					</view>
				</view>
			</view>
		</view>
	</u-popup>
</template>

<script>
	import {
		mapState
	} from 'vuex'
	import {
		createQrCode
	} from '@/common/api.js'
	export default {
		props: {
			storeInfo: {
				type: Object,
				default: () => {}
			}
		},
		data() {
			return {
				saveIcon: require('../../static/download.png'),
				copyLink: require('../../static/copyLink.png'),
				goodsIcon: require('../../static/goodsIcon.png'),
				qrCode: "",
				visiable: false,
				screen_height: 0,
				screen_width: 0
			}
		},
		computed: {
			...mapState(['$userInfo'])
		},
		created() {
			this.screen_height = uni.getSystemInfoSync().windowHeight;
			this.screen_width = uni.getSystemInfoSync().windowWidth / 375;
			
			console.log(this.screen_height,'screen_height');
		},
		methods: {
			// 店铺二维码分享
			createQrCodeFun() {
				uni.showLoading({
					title: '二维码加载中...',
					mask: true
				})
				createQrCode({
					path: 'pages/home/storePage/index?userGroupAuthId=' + this.storeInfo.userGroupAuthId,
					width: 500
				}).then(res => {
					const {
						filePath
					} = res.data || {} 
                    // 二维码图片,接口可使用网络地址模拟       
					this.qrCode = filePath
					// 得到二维码绘画
					this.setStopter();
				}).finally(() => {
					uni.hideLoading();
				})
			},
			// 复制链接
			handleCopyLink() {
				// #ifdef MP-WEIXIN
				var shareText = '【' + this.storeInfo.merchantName + '】' + '店铺欢迎您##长按复制此条消息,打开亿联乐购小程序首页即可跳转##' + this
					.storeInfo.userGroupAuthId
				uni.setClipboardData({
					data: shareText,
					showToast: false,
					success(res) {
						console.log("success:" + JSON.stringify(res));
						uni.showToast({
							title: '复制成功',
							icon: 'success'
						})
					},
					fail: () => {
						uni.showToast({
							title: '复制失败',
							icon: 'error'
						})
					},
					complete: () => {}
				})
				// #endif
			},
			//显示
			showCanvas() {
				this.visiable = true
				// 得到二维码绘画
				this.createQrCodeFun()
			},
			// 点击关闭
			hiddenCanvas() {
				this.visiable = false
			},
			// 绘制海报
			async setStopter() {
				uni.showLoading({
					title: '加载中...',
					mask: true
				})
				var _this = this
				var ctx = uni.createCanvasContext('posterid', _this) //创建画笔
// 自适应屏幕关键
				let rpx = this.screen_width
				ctx.drawImage('/static/share/share.png', 20 * rpx, 0, 330 * rpx, 380 * rpx);
				this.canvasFont(ctx, 16 * rpx, '#2D2D2D', this.storeInfo.merchantName, 100 * rpx, 50 * rpx)
				this.drawRoundRect(ctx, 90 * rpx, 70 * rpx, 192 * rpx, 192 * rpx, 12 * rpx, '#F5F5F5')
				let banerQrCode = await this.downloadImage(this.qrCode)
				if (banerQrCode.tempFilePath) {
					ctx.save()
					ctx.drawImage(banerQrCode.tempFilePath, 100 * rpx, 80 * rpx, 172 * rpx, 172 * rpx);
					ctx.restore()
				}
				this.canvasFont(ctx, 14 * rpx, '#999999', '(微信扫描二维码即可进入)', 100 * rpx, 280 * rpx)
				ctx.drawImage('../../static/goodsIcon.png', 265 * rpx, 290 * rpx, 50 * rpx, 50 * rpx);
				const {
					portraitFile,
					userName = "亿联乐购用户"
				} = this.$userInfo
				if (portraitFile && portraitFile.staticPath) {
					let userPortraitFile = await this.downloadImage(portraitFile.staticPath)
					ctx.save()
					ctx.drawImage(userPortraitFile.tempFilePath, 50 * rpx, 300 * rpx, 32 * rpx, 32 * rpx);
					ctx.restore()
				} else {
					ctx.drawImage('/static/share/user.png', 50 * rpx, 300 * rpx, 32 * rpx, 32 * rpx)
				}
				this.canvasFont(ctx, 12 * rpx, '#2D2D2D', userName, 90 * rpx, 320 * rpx)

				// ctx.draw()
				ctx.draw(true, () => {
					uni.hideLoading()
				})
				console.log('绘画完成')
			},
			canvasFont(ctx, fs, color, txt, x, y) { //绘制文字
				ctx.setFontSize(fs)
				ctx.setFillStyle(color)
				ctx.fillText(txt, x, y)
			},
			//圆角矩形
			drawRoundRect(ctx, x, y, width, height, radius, color) {
				ctx.save();
				ctx.beginPath();
				ctx.setFillStyle(color);
				ctx.setStrokeStyle(color)
				ctx.setLineJoin('round'); //交点设置成圆角
				ctx.setLineWidth(radius);
				ctx.strokeRect(x + radius / 2, y + radius / 2, width - radius, height - radius);
				ctx.fillRect(x + radius, y + radius, width - radius * 2, height - radius * 2);
				ctx.stroke();
				ctx.closePath();
			},
			downloadImage(url) { //绘制网络图片,网络图片需要先缓存到本地再绘制
				return new Promise((resolve, reject) => {
					uni.downloadFile({ // 还可以使用 uni.getImageInfo 方法
						url: url,
						success: (res) => {
							return resolve(res)
						},
						fail: (err) => {
							return reject(err)
						}
					})
				})
			},
			// 保存图片手机本地(二维码)
			saveImageToPhotosQrCode() {
				uni.showLoading({
					title: '二维码下载中'
				});
				const that = this;
				uni.downloadFile({
					url: that.qrCode, //二维码的地址
					success: function(res) {
						const tempFilePath = res.tempFilePath //通过res中的tempFilePath 得到需要下载的图片地址
						uni.saveImageToPhotosAlbum({
							filePath: tempFilePath,
							success: () => {
								uni.hideLoading();
								uni.showToast({
									title: '二维码已存入相册'
								});
							},
							fail: () => {
								uni.hideLoading();
								uni.showToast({
									title: '下载失败',
									icon: 'error'
								});
							},
							complete: () => {}
						});
					}
				})
			},
			// 保存海报
			saveImageToPhotosPoster() {
				uni.showLoading({
					title: '海报下载中...'
				});
				uni.canvasToTempFilePath({
					canvasId: 'posterid',
					success: function(res) {
						uni.saveImageToPhotosAlbum({
							filePath: res.tempFilePath,
							success(result) {
								uni.hideLoading()
								uni.showToast({
									title: '海报已存入相册',
									icon: 'success',
									duration: 2000
								})
							},
							fail: () => {
								uni.hideLoading()
							}
						})
					},
					complete(res) { //不管成功或者失败都会执行
						console.log('canvas转成图片结果', res)
					}
				}, this);
			},
			//保存海报和二维码
			saveImageToPhotosAlbumFun(flag) {
				if (flag === 100) {
					// 保存二维码
					this.saveImageToPhotosQrCode()
				} else {
					// 保存海报
					this.saveImageToPhotosPoster()
				}
			},
			//保存图片到相册
			savePoster(flag) {
				const that = this;
				// #ifdef MP-WEIXIN
				uni.getSetting({
					success: res => {
						if (res.authSetting['scope.writePhotosAlbum']) {
							that.saveImageToPhotosAlbumFun(flag)
						} else {
							uni.authorize({
								scope: 'scope.writePhotosAlbum',
								success: () => {
									that.saveImageToPhotosAlbumFun(flag)
								},
								fail: () => {
									uni.showModal({
										title: '提示',
										content: '请先在设置页面打开“保存相册”使用权限',
										confirmText: '去设置',
										cancelText: '算了',
										success: data => {
											if (data.confirm) {
												uni.openSetting();
											}
										}
									});
								},
								complete: res => {}
							});
						}
					}
				});
				// #endif
			}
		}
	}
</script>

<style lang="scss" scoped>
	// 边框样式
	button::after {
		border: 0;
	}

	.shareModel {
		width: 100%;
		background-color: #F5F5F5;
		color: #2D2D2D;

		.title {
			padding: 32rpx;
			text-align: center;
			font-size: 32rpx;
			font-weight: bold;
		}

		.share-container {
			margin: 0 80rpx 24rpx;
			padding: 32rpx;
			height: 100%;
			background: rgba(255, 255, 255, 0.39);
			box-shadow: 0 6rpx 20rpx rgba(110, 108, 108, 0.1);
			border-radius: 24rpx;

			.merchant-info {
				display: flex;
				flex-direction: column;
				justify-content: center;
				align-items: center;

				.merchantName {
					margin-bottom: 48rpx;
					font-weight: bold;
					font-size: 32rpx;
				}

				.tip {
					padding: 24rpx 0 48rpx;
					color: #999999;
					font-size: 24rpx;
				}

				.store-img {
					padding: 20rpx;
					background-color: #F5F5F5;

					.img {
						width: 380rpx;
						height: 380rpx;
					}
				}
			}

			.user-info {
				display: flex;
				align-items: center;
				justify-content: space-between;

				.header-name {
					display: flex;
					align-items: center;

					text {
						margin-left: 12rpx;
					}
				}
			}
		}

		.share-bot {
			width: 100%;
			background: #FFFFFF;

			.share-btns {
				display: flex;
				justify-content: space-around;
				align-items: center;
				width: 100%;
				padding: 30rpx 0;

				.btns-list,
				.btns-share,
				.btns-box {
					display: flex;
					flex-direction: column;
					justify-content: center;
					align-items: center;
					background-color: #FFFFFF;

					text {
						color: #2D2D2D;
						font-size: 28rpx;
						margin-top: 8rpx;
					}
				}
			}
		}
	}
</style>

父组件使用

父组件引入
<share-model-canvas ref="poster" :storeInfo="merchantInfo"></share-model-canvas>

<script>
import ShareModelCanvas from './shareModel/share-canvas.vue'

 //显示绘制店铺海报
sharePoster() {
	// canvas操作
	this.$refs.poster.showCanvas()
}
</script>

效果图

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

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

相关文章

【机器学习】主成分分析实现案例 (PCA)

一、说明 这篇文章的目的是提供主成分分析&#xff08;PCA&#xff09;的完整和简化的解释。我们将逐步介绍它是如何工作的&#xff0c;这样每个人都可以理解并使用它&#xff0c;即使是那些没有强大数学背景的人。 PCA是网络上广泛覆盖的机器学习方法&#xff0c;并且有一些关…

CentOS7下载并安装mysql-8.0.33

CentOS7下载并安装mysql-8.0.33 一、官网下载mysql-8.0.33 MySQL下载路径 MySQL :: Download MySQL Community Server 自己百度mysql官网下载的话直接按照完整路径指示下载即可&#xff0c;如果点击上面的连接下载mysql的话&#xff0c;直接按照4、5、6步骤选择适合自己linu…

Vue--》Vue3打造可扩展的项目管理系统后台的完整指南(八)

今天开始使用 vue3 ts 搭建一个项目管理的后台&#xff0c;因为文章会将项目的每一个地方代码的书写都会讲解到&#xff0c;所以本项目会分成好几篇文章进行讲解&#xff0c;我会在最后一篇文章中会将项目代码开源到我的GithHub上&#xff0c;大家可以自行去进行下载运行&…

从小白到大神之路之学习运维第49天---第三阶段----MHA高可用集群数据库的安装部署

第三阶段基础 时 间&#xff1a;2023年6月29日 参加人&#xff1a;全班人员 内 容&#xff1a; MHA高可用数据库集群 目录 一、MHA基础 &#xff08;一&#xff09;简介 &#xff08;二&#xff09;发挥过程 &#xff08;三&#xff09;组成 &#xff08;四&#x…

Quiz 5: Loops and Iterations | Python for Everybody 配套练习_解题记录

文章目录 课程简介Quiz 5: Loops and Iterations 单选题&#xff08;1-10&#xff09;编程题Exercise 5.2 课程简介 Python for Everybody 零基础程序设计&#xff08;Python 入门&#xff09; This course aims to teach everyone the basics of programming computers using…

C++语法练习(牛客题库)——练习1

1. 下列程序的运行结果是 1*2 3*4&#xff0c;那么横线处缺失程序可以是&#xff08;&#xff09; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <iostream> using namespace std; class Test{ public: Test(int a, int b) { …

【运维知识进阶篇】zabbix5.0稳定版详解6(zabbix自动化监控:自动发现+自动注册+监控项目主动式)

本篇文章继续给大家介绍zabbix自动化监控&#xff0c;包括zabbix自动注册&#xff0c;zabbix自动发现&#xff0c;将主机添加进服务端之后需要做的监控项目更改为主动式&#xff0c;zabbix说多不多&#xff0c;说少不少&#xff0c;其实远没有监控那么简单&#xff0c;更深层次…

【运维知识进阶篇】zabbix5.0稳定版详解7(zabbix分布式监控:使用场景+功能详解+快速部署+基本使用)

如果你有几百上千台客户端的数据需要上报给zabbix服务端&#xff0c;即便是你做了主动注册&#xff0c;监控项目主动式&#xff0c;那服务端压力还是会很大&#xff0c;所以我们可以考虑zabbix分布式监控。 zabbix proxy可以代替zabbix server收集性能和可用性数据&#xff0c…

【HTTP 协议1】图文详解 HTTP 请求和应答报文

文章目录 前言一、认识 HTTP 协议1, 什么是 HTTP 协议2, HTTP 协议的报文格式 二、HTTP 请求报文1, 认识方法1.1, GET 和 POST 辨析(重点)1.2, 其他方法 2, 认识 URL3, 认识 Header3.1, Host3.2, Content-Length3.3 Content-Type3.4, User-Agent3.5, Referer3.6, Cookie(重点) …

源代码|大屏可视化系统 数据可视化

代码拿来即可用&#xff0c;按照下文步骤配置&#xff0c;傻瓜式教程&#xff0c;几分钟即可搞定。 需要代码源文件&#xff0c;请移步至gzh【李桥桉】&#xff0c;s辛【可视化】。 可视化效果图 运行环境&#xff1a;VScode 文末附《大屏可视化系统》源代码获取方式~ 一、打…

数据结构--顺序栈的实现

数据结构–顺序栈的实现 顺序栈的定义 顺序栈的定义代码实现 #define MaxSize 10 typedef struct {ElemType data[MaxSize]; //静态数组存放栈中元素int top; //栈顶指针 } SqStack;int main() {SqStack S; //声明一个顺序栈(分配空间)//... ...return 0; }一些常见操作 初始…

大数据的金融数据读取及分析(-)

由于考虑商业数据问题&#xff0c;我们用开源数据做演示 一.tushare开源数据 Tushare是一个免费、开源的python财经数据接口包。主要实现对股票等金融数据从数据采集、清洗加工到数据存储的过程&#xff0c;能够为金融分析人员提供快速、整洁、和多样的便于分析的数据&#x…

postgresql_internals-14 学习笔记(七)—— parallel 并行

不完全来自这本书&#xff0c;把查到的和之前的文章重新汇总整理了一把。 一、 核心参数 几个容易弄混的进程和参数&#xff0c;关系图如下 1. max_worker_processes 整个实例可以同时运行的Background workers Processes最大数量默认值为8&#xff0c;设置为0表示禁用并行&…

STM32与树莓派:嵌入式系统开发与教育计算的区别

STM32和树莓派是两种不同的硬件平台&#xff0c;用于不同的应用领域。 STM32&#xff1a;STM32是一系列由STMicroelectronics&#xff08;意法半导体&#xff09;生产的32位ARM Cortex-M微控制器。它们被广泛用于嵌入式系统开发&#xff0c;包括消费电子产品、工业自动化、汽车…

CNN池化总结(最大池化与平均池化)

目录 概念 两种主要池化方式 最大池化 平均池化 尺寸变化过程 池化优点 总结 概念 池化&#xff08;Pooling&#xff09;&#xff0c;用于减小卷积神经网络&#xff08;CNN&#xff09;或其他类型神经网络的特征图&#xff08;Feature Map&#xff09;的尺寸&#xff0…

java 网络教学平台Myeclipse开发mysql数据库web结构jsp编程计算机网页项目

一、源码特点 JSP 网络教学平台 是一套完善的系统源码&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;以及相应配套的设计文档&#xff0c;系统主要采用B/S模式开发。 研究的基本内容是基于Web的网络教学平台&…

【SWAT水文模型】SWAT-CUP参数率定过程问题总结

SWAT-CUP参数率定过程问题总结 Q1 SWAT-CUP中calibrate按钮一直是灰色无法点击?1.1 问题描述1.2 解决办法 Q2 “SWAT”不是内部命令1.1 问题描述1.2 解决办法 参考 Q1 SWAT-CUP中calibrate按钮一直是灰色无法点击? 1.1 问题描述 软件是从2W2E上下载的SWAT-CUP2019&#xff…

XILINX ZYNQ 7000 BOOT

参考UG585 内容 下面这张图是ZYNQ启动的关键流程 1.POR表示硬件复位&#xff0c;不关心Power-up也就是说冷热启动都行。Nor-POR就是非POR复位&#xff0c;有点软件应用复位的意思。 2.POR复位会复位所有寄存器。并且采集 HardWare boot pin的状态。这点很关键&#xff0c; 3.是…

mysql一些常用函数

group_concat()函数首先根据group by指定的列进行分组&#xff0c;并且用分隔符分隔&#xff0c;将同一个分组中的值连接起来&#xff0c;返回一个字符串结果。 group_concat([distinct] 字段名 [order by 排序字段 asc/desc] [separator 分隔符])-- 指定排序方式和分隔符 se…

STM32F407 滴答定时器

介绍STM32F407滴答定时器配置方法、使用方式&#xff0c;封装延时函数得到精确的时间。 【1】介绍滴答定时器的章节 STM32F407参考手册中第10章介绍了滴答定时器的校准值。 M4权威指南介绍滴答定时器的章节&#xff0c;M3权威指南中与M4权威指南中的介绍一样。 【2】滴答定时…