微信小程序uniapp分享生成海报带二维码,封装为组件

一、首先看一下效果,点击分享生成海报,弹出海报,包括一些信息,图片以及小程序二维码,长按可保存到本地;

二、下面为封装好的生成海报的组件;

<template>
	<view class="container">
		<!-- 生成海报的canvas -->
		<view  class="my-canvas-box" @touchmove.stop.prevent :class="posterInfo.status ? 'show' : 'hide'" @click="posterInfo.status = false">
			<canvas class="my-canvas" canvas-id="myCanvas" @longpress.stop="saveSharePic"></canvas>
			<view class="canvas-tip">长按可保存海报</view>
		</view>
	</view>
</template>

<script>
export default {
	name: 'PosterGenerator',
	props:{
		shopInfo: {
		  type: Object,
		},
		operatemerId:{
			type:String,
		},	
	},
	data() {
		return {
			// 用来控制canvas遮罩层的显示与隐藏
			posterInfo: {
				status: false,
			},
			// shopInfo: {},
			bufferImg: '',
			token: '',
			codeImg: '',
		};
	},
	created() {
		this.token = uni.getStorageSync('token');
		
	},
	methods: {
		// 获取 access_token
		async getAccessToken() {
		    const appid = 'wx0f1dc3df604bd298';
		    const secret = '65db0115543850fd3deca0e23de1961f';
		    const result = await uni.request({
		        method: "GET",
		        url: `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${secret}`
		    });
		    const access_token = result.data.access_token;
			// 获取到 access_token 后获取二维码
			// 注意 access_token 参数是必须放在url后面 其余参数 要在data里面
		    const qrResult = await uni.request({
		        method: "POST",
		        responseType: 'arraybuffer', // 注意一定要加 不然返回的Buffer流会乱码 导致无法转base64
		        url: `https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=${access_token}`,
		        data: {
		            page: 'subPages/shop-detail/shop-detail',// 需要打开的页面路径
		            scene: this.operatemerId,// 这个是需要传递的参数
		        }
		    });
			// 拿到buffer流 通过wx.arrayBufferToBase64 转成base64 在页面展示
			// 如果请求时不加 responseType: 'arraybuffer' 拿到的buffer流转码会失败
		    this.bufferImg = "data:image/png;base64," + wx.arrayBufferToBase64(qrResult.data);
			// 将bse64图片上传给后端,获取到网络地址
		    this.bindUploadBase64(this.bufferImg);
		},
		// 上传二维码图片到后端
		async bindUploadBase64(base64Img) {
			// 将Base64 编码的图片数据转换为一个临时文件路径
		    const filePath = this.base64ToFilePath(base64Img);
		    if (filePath) {
		        const uploadResult = await uni.uploadFile({
		            url: this.app.api_url + '/file/upload',
		            filePath: filePath,
		            name: "file",
		            header: {
		                "content-type": "multipart/form-data",
		                'Authorization': 'Bearer ' + this.token
		            }
		        });
		        const tip = JSON.parse(uploadResult.data);
		        if (tip.code == 0) {
		            this.codeImg = tip.data.url;
		        } else {
		            console.log('上传失败');
		        }
		    }
		},
		// 将Base64 编码的图片数据转换为一个临时文件路径
		base64ToFilePath(base64Img) {
			console.log('base64Img',base64Img)
			console.log('base64Img.replace',base64Img.replace(/^data:image\/\w+;base64,/, ""),)
		    const filePath = `${wx.env.USER_DATA_PATH}/temp_image.png`;
		    wx.getFileSystemManager().writeFile({
		        filePath: filePath,
		        data: base64Img.replace(/^data:image\/\w+;base64,/, ""),
		        encoding: 'base64',
		        success: () => {
		            console.log('文件写入成功', filePath);
		        },
		        fail: (err) => {
		            console.error('文件写入失败', err);
		        }
		    });
		    return filePath;
		},
		
		async generatePoster() {
		    await this.getAccessToken();
		    const user = uni.getStorageSync('user');
			// 这里是创建 canvas 绘图上下文
		    const context = uni.createCanvasContext('myCanvas',this);
			// 这里可以根据自己的需求显示加载动画
		    uni.showToast({
		        title: '正在生成海报,请稍后',
		        icon: 'none',
		        duration: 3000
		    });
			// 给整个canvas填充白色背景(这个如果不加上的话,在APP端生成的海报没有白色背景)
		    context.setFillStyle('#ffffff');
		    context.fillRect(0, 0, 500, 900);
		    context.draw();
			// 绘制用户昵称
		    context.setFontSize(14);
		    context.setFillStyle('#000000');
			// 这里根据自己的项目填写用户昵称的字段
		    context.fillText(user.username, 100, 48);
		    context.setFontSize(12);
		    context.setFillStyle('#999999');
		    context.fillText('的店铺分享', 100, 68);
		    this.drawText(this.shopInfo.merchantsName, 20, 379, context);
			// 绘制头像
			// url: '用户的头像地址(一定要是网络路径)',
		    const avatarRes = await uni.downloadFile({ url: user.avatar });
		    context.save();
			 // 这个就是绘制圆形头像
		    context.beginPath();
		    context.arc(50, 50, 30, 0, 2 * Math.PI);
		    context.clip();
		    context.drawImage(avatarRes.tempFilePath, 20, 20, 60, 60);
		    context.restore();
		    context.draw(true);
			// 绘制商店详情
		    const shopImgRes = await uni.downloadFile({ url: this.shopInfo.imgPathL[0] });
		    context.drawImage(shopImgRes.tempFilePath, 15, 92, 245, 245);
		    context.draw(true);
			// 绘制二维码
			// this.codeImg是上面获取到的图片
		    const qrImgRes = await uni.downloadFile({ url: this.codeImg });
		    context.drawImage(qrImgRes.tempFilePath, 165, 360, 100, 100);
		    context.draw(true);
			// 绘制完成,让canvas显示【这里看自己项目,是否有loading动画】
		    this.posterInfo.status = true;
		},
		
		// 商品名称文字换行
		drawText(context, x, y, canvas) {
			let strArr = [];
			let n = 11;
			for (let i = 0, l = context.length; i < l / n; i++) {
				let a = context.slice(n * i, n * (i + 1));
				strArr.push(a);
			}
			strArr.forEach((item, index) => {
				// 限制只能显示4行文字
				if (index > 3) {
					return;
				}
				y += 20;
				canvas.setFontSize(12);
				canvas.setFillStyle('#333333');
				canvas.fillText(item, x, y);
			});
		},
		// 长按保存生成的海报
		saveSharePic() {
			var that=this;
			uni.showModal({
				title: '提示',
				content: '确定要保存分享海报吗?',
				success: function(res) {
					if (res.confirm) {
						console.log('确认')
						// canvas生成图片
						uni.canvasToTempFilePath({
							// 这里修改保存的图片格式
							fileType: 'jpg',
							canvasId: 'myCanvas',
							quality: 1,
							success: function(res) {
								// 保存到本地
								uni.saveImageToPhotosAlbum({
									filePath: res.tempFilePath,
									success: function() {
										uni.showToast({
											title: '保存海报成功',
											icon: 'none',
											duration: 3000
										});
									},
									fail: function() {
										uni.showToast({
											title: '保存海报失败',
											icon: 'none',
											duration: 3000
										});
									}
								});
							},
							fail: function(err) {
								console.log('保存失败',err)
							}
						},that);
					}
				}
			});
		},
	}
};
</script>

<style lang="scss" scoped>
.my-canvas-box {
	width: 750rpx;
	height: 100%;
	position: fixed;
	background-color: rgba(0, 0, 0, 0.6);
	z-index: 99;

	&.hide {
		display: none;
	}

	&.show {
		display: block;
	}
	.canvas-tip {
		color: #ffffff;
		font-size: 24rpx;
		margin-top: 30rpx;
		text-align: center;
	}
	/* #ifdef MP-WEIXIN */
	.my-canvas {
		width: 550rpx;
		height: 950rpx;
		background-color: #ffffff;
		margin: 20rpx auto;
	}
	/* #endif */

	/* #ifdef APP-PLUS || H5 */
	.my-canvas {
		width: 550rpx;
		height: 950rpx;
		background-color: #ffffff;
		margin-top: 220rpx auto;
	}
	/* #endif */
}
.container {
	height: 100%;
	width: 100%;
}
</style>

三、在父组件中引用该组件

<view class="relay"  @click="generatePoster">
	<button>生成海报</button>
</view>
<!-- 生成海报组件,两个参数根据实际情况修改 -->

<PosterGenerator ref="posterGenerator"   :shopInfo="shopInfo" :operatemerId="operatemerId" />


import PosterGenerator from '@/subPages/components/PosterGenerator/PosterGenerator.vue';

components:{
	PosterGenerator
},
// 分享生成海报
generatePoster() {
	// 调用 PosterGenerator 组件中的 generatePoster 方法
	this.$refs.posterGenerator.generatePoster();
},

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值