uni-app/js/小程序/生成支付二维码图片,类似于支付宝和微信商家码

业务需求

一个电子商务公司需要一个支付功能,该支付功能通过微信扫码或者支付宝扫码实现的,并且该二维码商户可以下载下来,类似于微信商家码。如下图,鉴于公司相关的保密协议,我马赛克了头部和中间的商标相关说明文字。由于是用的uni-app,原生的js操作是无法实现的,因为安卓和ios是没有dom这个概念的也没有实现canvas的一些底层API,为此需要我们自己手撕uni-app的canvas相关的API。
在这里插入图片描述

实现思路介绍

上图呢是一个中间二维码,为了生成这个二维码,我才用了uni-app的第三方插件库“tki-qrcode”这个插件。背景是一个绿色的正方形,这个可以用图片或者自己用canvas画布绘制一个。顶部是一个公司的logo加说明文字,底部呢是支付宝和微信二维码的logo,要把图片绘制到canvas画布上,就只需调用uni-app的drawImage这个方法就行。把文字绘制到canvas上就调用fillText就行了。绘制完所有的部分,然后调用uni-app的uni.canvasToTempFilePath(object, component)这个方法就行了。
要实现生成商家码并保存到相册的功能有很多方法,这里我介绍一种方法,自认为是最快的方法。具体方法如下。(窃笑)

具体实现步骤

引入tki-qrcode组件

tki-qrcode组件地址 插件下载地址

import tkiQrcode from "@/components/tki-qrcode/tki-qrcode.vue"
export default {
    components: {tkiQrcode}
}
<tki-qrcode v-if="ifShow"
			cid="qrcode1" 
			ref="qrcode" 
			:val="val" 
			:size="size" 
			:unit="unit"  
			:icon="icon" 
			:iconSize="iconsize" 
			:lv="lv" //这里填入你要生成的链接地址
			:onval="true" 
			:loadMake="true" //组件加载完成后自动生成二维码
			:usingComponents="true" 
			@result="resultFunc" //生成二维码base64编码格式的图片
/>
// 编写二维码生成函数
resultFunc:function(path){
				this.path = path;//二维码base64编码
				if(path!==undefined){
				//只有当二维码生成时,我们才去绘制收款码否则收款码中间的二维码将无法绘制到canvas画布上
					this.drawSKM();//绘制整个商家码
				}
				console.log('this.path',this.path);
			}
// 编写收款码顶部、底部、中间背景图
 drawSKM:function(){
				if(this.path){
					var context = uni.createCanvasContext('firstCanvas');
					context.setFillStyle("#fff");
					context.fillRect(20,0,380,60);
					context.setTextBaseline('middle');
					context.setFillStyle('#00A757');
					context.setFontSize(20);
					context.fillText('顶部商家说明文字',175,30);
					context.drawImage('商家logo地址',145,18,30,26);
					context.setFillStyle('#00A757');
					context.fillRect(20,60,380,380);
					context.closePath();
					//开启新的绘制
					context.setFillStyle('#fff');
					context.setFontSize(40);
					context.fillText('请扫码付款',105,100);
					context.fillRect(90,130,240,260);
				    context.drawImage(this.path,110,150,200,200);//this.path就是中间二维码的base64编码
					context.setFontSize(18);
					context.setFillStyle('#000');
					context.setTextAlign('center');
					context.setTextBaseline('middle');
					context.fillText(`商家名字收款码`,210,370);
					//绘制底部logo
					context.setFillStyle('#fff');
					context.fillRect(20,440,380,60);
					context.drawImage('支付宝logo地址',85,453,36.5,36.5);
					context.beginPath();
					context.setStrokeStyle('#EEEEEE');
					context.moveTo(210,450);
					context.lineTo(210,490);
					context.stroke();
					context.closePath();
					context.drawImage('微信logo地址',290,453,36,31);
					context.draw();
				}
			},

注意事项

1、由于我们需要等待中间二维码生成后,才能去绘制整个商家码,所以需要在二维码生成base64编码的时候进行判断,判断base64编码有没有产生,产生了则去执行绘制整个商家码。
2、鉴于各个手机屏幕尺寸不一,所以大家可以叫美工将二维码的背景交由美工绘制出来,生成无损压缩图片(这里需要注意图片格式,否则将图片填充到二维码上将有点儿模糊)。
3、我的方案在2340*1080像素的手机上测试通过了,ios也测试通过了,如果大家对生成的商家码质量要求很高,可以参考我的写法进行修改!

整个源码

<template>
	<view class="pay-contanier">
		
		<view class="pay-box">
			<view class="code-title">
				<view class="code-logo">
					<image src="../../../static/images/icon_logo.png" mode=""></image>
					<span>小厨子</span>
				</view>
			</view>
			<view class="scan-code">
				<view class="scan-span">请扫码付款</view>
				<view class="scan-box">
					<tki-qrcode v-if="ifShow"
								cid="qrcode1" 
								ref="qrcode" 
								:val="val" 
								:size="size" 
								:unit="unit"  
								:icon="icon" 
								:iconSize="iconsize" 
								:lv="lv" 
								:onval="onval" 
								:loadMake="loadMake" 
								:usingComponents="true" 
								@result="resultFunc"
								/>
					<view class="scan-user">小厨子收款码</view>
				</view>
			</view>
			
			<view class="code-zf">
				<view class="zf-zfb">
					<image src="../../../static/images/jingying/icon_zfbzf.png" mode=""></image>
				</view>
				<view class="zf-wx">
					<image src="../../../static/images/jingying/icon_wxzf.png" mode=""></image>
				</view>
			</view>
		</view>	
		<view id="canvasImage">
			 <canvas style="width: 750rpx; height: 600px;margin: 0 auto;" canvas-id="firstCanvas" id="firstCanvas"></canvas>
		</view>
			<button @click="saveSKMImage">保存到相册</button>
	</view>
</template>

<script>
	import tkiQrcode from "@/components/tki-qrcode/tki-qrcode.vue";
	import qr from "@/components/tki-qrcode/wxqrcode.js"
	export default {
	    components: {
			tkiQrcode
		},
	    data() {
			return {
				ifShow: true,
				val: '', // 要生成的二维码值
				size: 400, // 二维码大小
				unit: 'upx', // 单位
				icon: '../../../static/images/icon_logo.png', // 二维码图标
				iconsize: 60, // 二维码图标大小
				lv: 3, // 二维码容错级别 , 一般不用设置,默认就行
				onval: true, // val值变化时自动重新生成二维码
				loadMake: true, // 组件加载完成后自动生成二维码
				src: '' ,// 二维码生成后的图片地址或base64
			};
		},
		onReady() {
			this.resultFunc();
		},
		onLoad() {
			var shopId = uni.getStorageSync('shopId');
			var merchantsId = uni.getStorageSync('merchantsId');
			this.shopName = uni.getStorageSync("shopName");
			this.val ='这里填写自己的地址和参数';	
		},
		methods:{
			saveSKMImage:function(){
				uni.canvasToTempFilePath({
					x:20,
					y:0,
					width:370,
					height:500,
					canvasId:'firstCanvas',
					success(res) {
						uni.saveImageToPhotosAlbum({
							filePath:res.tempFilePath,
							success:function(){
								uni.showToast({
									icon:'success',
									title:'保存成功,请到相册中查看!'
								})
							}
						})
						console.log('生成的图片base64',res.tempFilePath);
					}
				})
			},
			drawSKM:function(){
				if(this.path){
					var context = uni.createCanvasContext('firstCanvas');
					context.setFillStyle("#fff");
					context.fillRect(20,0,380,60);
					context.setTextBaseline('middle');
					context.setFillStyle('#00A757');
					context.setFontSize(20);
					context.fillText('小厨子',175,30);
					context.drawImage('../../../static/images/icon_logo.png',145,18,30,26);
					context.setFillStyle('#00A757');
					context.fillRect(20,60,380,380);
					context.closePath();
					//开启新的绘制
					context.setFillStyle('#fff');
					context.setFontSize(40);
					context.fillText('请扫码付款',105,100);
					context.fillRect(90,130,240,260);
					context.drawImage(this.path,110,150,200,200);
					context.setFontSize(18);
					context.setFillStyle('#000');
					context.setTextAlign('center');
					context.setTextBaseline('middle');
					context.fillText(`小厨子收款码`,210,370);
					//绘制底部logo
					context.setFillStyle('#fff');
					context.fillRect(20,440,380,60);
					context.drawImage('../../../static/images/jingying/icon_zfbzf.png',85,453,36.5,36.5);
					context.beginPath();
					context.setStrokeStyle('#EEEEEE');
					context.moveTo(210,450);
					context.lineTo(210,490);
					context.stroke();
					context.closePath();
					context.drawImage('../../../static/images/jingying/icon_wxzf.png',290,453,36,31);
					context.draw();
				}
				
			},
			resultFunc:function(path){
				this.path = path;
				if(path!==undefined){
					this.drawSKM();
				}
				console.log('this.path',this.path);
			}
		}
	}
</script>

<style lang="scss" scoped>
	page{
		background-color: rgb(245,245,245);
	}
	.pay-contanier{
		// text-align: center;
		.pay-box{
			width: 686rpx;
			height: 956rpx;
			background: #FFFFFF;
			box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
			opacity: 1;
			border-radius: 8px;
			margin: 20rpx auto;
			.code-title{
				width: 100%;
				height: 108rpx;
				display: flex;
				justify-content: center;
				align-items: center;
				.code-logo{
					display: flex;
					justify-content: center;
					align-items: center;
					image{
						width: 52rpx;
						height: 52rpx;
					}
					span{
						font-size: 36rpx;
						font-weight: 600;
						color: #00A757;
					}
				}
				.code-txt{
					margin-left: 20rpx;
					font-weight: normal;
					font-size: 36rpx;
					color: #000000;
					opacity: 1;
				}
			}
			.scan-code{
				width: 100%;
				height: calc(956rpx - 228rpx);
				background-color: #00A757;
				display: flex;
				align-items: center;
				flex-direction: column;
				.scan-span{
					font-size: 80rpx;
					color: #FFFFFF;
					opacity: 1;
				}
				.scan-box{
					width: 460rpx;
					height: 520rpx;
					background: #FFFFFF !important;
					opacity: 1;
					display: flex;
					justify-content: center;
					flex-direction: column;
					align-items: center;
					margin-top: 40rpx;
					.tki-qrcode{
						margin-top: 10rpx;
					}
					.scan-user{
						font-size: 32rpx;
						font-weight: 600;
						padding-top: 10rpx;
					}
				}
			}
			.code-zf{
				width: 100%;
				height: 120rpx;
				display: flex;
				justify-content: center;
				align-items: center;
				.zf-zfb{
					width: 50%;
					height: 68rpx;
					border-right: 4rpx solid #EEEEEE;
					text-align: center;
					image{
						width: 65rpx;
						height: 65rpx;
					}
				}
				.zf-wx{
					width: 50%;
					height: 68rpx;
					text-align: center;
					image{
						width: 65rpx;
						height: 65rpx;
					}
				}
			}
		}
	}
	#canvasImage{
		 position: fixed;
		 top: -9999999999999rpx;
	}
	button{
		width: 80%;
		height: 100rpx;
		background: #2FAF48;
		color: #FFFFFF;
		display: flex;
		justify-content: center;
		align-items: center;

		position: fixed;
		bottom: 50rpx;
		margin-left: 80rpx;
		border-radius: 20rpx;
	}
</style>

结尾

如果该篇文章帮助到了你,还请给个三连,原创不易,转载请注明来处。博主身世贫寒,欢迎大家打赏!如遇遇到了问题,可以加我qq1822497204联系解决。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

挽枫blog

打赏是对知识的尊重!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值