文章主要记录uniapp开发公众号H5、APP、小程序过程中支付相关的微信支付、支付宝支付调用,支付失败处理,多端兼容性如状态栏背景色处理、H5页面参数传递转义处理,H5跨域处理,页面使用拖拽功能,并且拖拽不影响页面其它按钮点击等的操作。

uni-app微信支付、支付宝支付
首先要在微信支付商户平台申请接入对应的平台(APP,H5,小程序);支付宝支付也需要在支付宝开放平台申请对应的平台支付

1. 微信公众号中(H5)调用微信支付: 获取openid,引入微信公众平台API的微信H5支付JSSDK插件 或者 使用微信浏览器内置的onBrideReady(这种方式不需要引入JSSDK,但是只能在微信浏览器中使用)

// 引入微信JSSDK
var jweixin = require('@/js_sdk/jweixin-module@1.6.0.js')
export function toWxPay(res) {
// res为下单后端接口返回的数据,微信支付需要的参数(appId,timeStamp,nonceStr,package,signType,paySign)是后端接口返回的,下单时需要传当前用户的openid
   jweixin.config({
   	// debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
   	appId: res.third_data.appId, // 必填,公众号的唯一标识
   	timestamp: res.third_data.timeStamp, // 必填,生成签名的时间戳
   	nonceStr: res.third_data.nonceStr, // 必填,生成签名的随机串
   	signature: res.third_data.authSign, // 必填,签名,见附录1
   	jsApiList: ['chooseWXPay'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
   });

   jweixin.ready(function() {
   	// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
   	 jweixin.chooseWXPay({
   		appId: res.third_data.appId, //公众号名称,由商户传入
   		timestamp: res.third_data.timeStamp, //时间戳,自1970年以来的秒数
   		nonceStr: res.third_data.nonceStr, //随机串
   		package: res.third_data.package,
   		signType: res.third_data.signType, //微信签名方式:
   		paySign: res.third_data.paySign, //微信签名
   		success: function(res) {
   			// console.log('支付成功' + res)
   			uni.showToast({
   				title: '支付成功'
   			})
   			setTimeout(function() {
   				uni.navigateBack({
   					delta: 1
   				})
   			}, 1000)
   		},
   		cancel: function(res) {
   			// console.log('取消支付' + res)
   			uni.showToast({
   				title: '取消支付',
   				icon: 'none'
   			})
   		},
   		fail: function(res) {
   			// console.log('支付失败' + res)
   			uni.showToast({
   				title: '支付失败',
   				icon: 'none'
   			})
   		}
   	})
   });
   jweixin.error(function(res) {
   	console.log('身份验证失效' + res)
   });
}

// 微信浏览器内置支付方式,appid,timeStamp,nonceStr,package,signType,paySign参数值从接口获取
function onBridgeReady(res) {
 WeixinJSBridge.invoke(
   "getBrandWCPayRequest",
   {
     appId: "wx2421b1c4370ec43b", //公众号名称,由商户传入
     timeStamp: "1395712654", //时间戳,自1970年以来的秒数
     nonceStr: "e61463f8efa94090b1f366cccfbbb444", //随机串
     package: "prepay_id=u802345jgfjsdfgsdg888",
     signType: "RSA", //微信签名方式:
     paySign: "70EA570631E4BB79628FBCA90534C63FF7FADD89", //微信签名
   },
   function (res) {
     if (res.err_msg == "get_brand_wcpay_request:ok") {
       // 支付成功处理
     }
   }
 );
}

export function wxBridegePay(res){
   if (typeof WeixinJSBridge == "undefined") {
     if (document.addEventListener) {
       document.addEventListener("WeixinJSBridgeReady", onBridgeReady, false);
     } else if (document.attachEvent) {
       document.attachEvent("WeixinJSBridgeReady", onBridgeReady);
       document.attachEvent("onWeixinJSBridgeReady", onBridgeReady);
     }
   } else {
     onBridgeReady(res);
   }
}

2. 支付宝H5支付:通过支付宝扫码调起支付宝支付,后端配合获取用户buyer_id;下载或引入Alipay JSSDK,页面下单后接口返回对应的参数,再调用ap.tradePay唤起支付,有2种唤起方式,根据接口返回的参数类型调用

// 1.交易号唤起支付——tradeNO参数为页面下单后接口返回的交易号
function aliPay(tradeNO){
    ap.tradePay({ tradeNO: tradeNO }, function(res){
        if(res.resultCode == '9000'){
        	console.log("支付成功")
        }else{
            ap.alert('支付失败,'+res.resultCode);
        }
    });
}

// 2.订单字符串唤起支付——orderStr参数为页面下单后接口返回的交易字符串
function aliPay(orderStr){
    ap.tradePay({ orderStr: orderStr}, function(res){
        if(res.resultCode == '9000'){
        	console.log("支付成功")
        }else{
            ap.alert('支付失败,'+res.resultCode);
        }
    });
}

3. APP中调用微信支付、支付宝支付

export function appPay(orderInfo, provider) {
 // orderInfo包含的key值
 // orderInfo = {
 // 	"appid": objData.appid,
 // 	"noncestr": objData.noncestr,
 // 	"package": objData.package,
 // 	"partnerid": objData.partnerid,
 // 	"prepayid": objData.prepayid,
 // 	"timestamp": objData.timestamp,
 // 	"sign": resObj.sign,
 // }
// orderInfo为下单后端接口返回的数据,微信支付时provider为wxpay,支付宝支付时provider为alipay
 uni.requestPayment({
 	provider: provider,
 	orderInfo: orderInfo,
 	success: function(res) {
 		uni.showToast({
 				title: '支付成功'
 			})
 	},
 	fail: function(err) {
 		console.log(err)
 		showTishi('支付失败')
 	}
 });
}

微信支付调用出现错误 requestPayment:fail [payment微信:-1]General errors",“errCode”:-100,“code”:-100} 时问题排查:

  1. orderInfo 参数的key值全部为小写,并且为json格式
  2. provider值为wxpay
  3. 模拟器环境有时候调起成功后再多次调用也会出现这种情况,打包后就是正常的了
  4. 以上几种情况都确认无误基本上就是接口的问题和在微信商户配置的问题了,可能是配置的appid、签名等信息、申请时填写的app信息等不正确导致

uni-app请求封装
6. H5端跨域处理 —— 在manifest.json中新增跨域处理

"h5" : {
     "devServer" : {
         "port" : 9000,
         "proxy" : {
             "/api" : {
                 "target" : url,  // url为接口地址
                 "secure" : false,
                 "changeOrigin" : true,
                 "pathRewrite" : {
                     "^/api" : "/api"  // web-admin是接口前面统一的参数,在这里统一处理下,没有的不用""
                 }
             }
         }
     }
 }
 // 使用方法:假如接口地址为 "http://abc.com/api/login", 配置后直接写 "/api/login",在封装好的request.js文件中写法参考下面一条的H5情况
  1. 运行小程序模式时,需配置完整的url,在统一的request中处理。根目录下创建 utils/request.js 文件,在这里统一处理请求头、错误情况,文件代码如下
const BASE_URL = url // url是接口地址
export const request = (options) => {
	return new Promise((resolve, reject) => {
		// #ifdef MP-WEIXIN
		options.url= BASE_URL + options.url
		// #endif
		
		// #ifdef H5
		// '/api' 在上面一条里面跨域那里处理的
		options.url= '/api' + options.url
		// #endif
		
		if(options.url !='/user/login'){
			const token = uni.getStorageSync('token')
			if(token){
				options.header = {
					'authorization':token
				}
			}		
		}
		uni.request({
			url: options.url,
			method: options.method || 'GET',
			data: options.data || {},
			header: options.header ,
			success: (response) => {
				const res = response
				// 请求携带authorization的时候就更新authorization的值,没有就不处理
				if(res.header.authorization){
					uni.setStorageSync('token',res.header.authorization)
				}
				if(res.statusCode !== 200){
					uni.showToast({
						title: res.data.message,
					})
					// 根据实际返回的code处理,我的403和440为需要登录的状态,自动跳转登录页面
					if(res.statusCode == 403 || res.statusCode == 440){
						uni.removeStorageSync('token')
						uni.reLaunch({
							url: '../login/login'
						})
					}
				}
				resolve(res)	
			},
			fail: (error) => {
				uni.showToast({
					title: error.message
				})
				reject(error)
			}
		})
	})
}

H5特殊处理

  1. uni-app兼容APP、H5、小程序时,在H5中标题重复,在page.json中配置页面路径时,在page.json中设置H5的titleNView为false:
{
	"path": "pages/home/index",
	"style": {
		"navigationBarTitleText": "首页",
		"h5": {
			"titleNView": false
		}
	}
}
  1. H5页面底部tabbar遮挡内容,设置元素style : padding-top、padding-bottom
padding-top: var(--window-top);
padding-bottom: var(--window-bottom);
  1. 参数转义处理:页面与页面直接传递对象参数:
uni.navigateTo({
	url: '/pages/news/list?item='+encodeURIComponent(JSON.stringify((this.infoData)))
})
// 接收页面:
onLoad(option){
	this.info= JSON.parse(decodeURIComponent(option.item))
	console.log(this.info,'000')
}

// 有时url参数被转义:decodeURIComponent()  进行反转义
function GetRequest() {
    var url = location.search; //获取url中"?"符后的字串
    var params= new Object();
    if (url.indexOf("?") != -1) {
        var str = url.substr(1);
        strs = str.split("&");
        for(var i = 0; i < strs.length; i ++) {
            params[strs[i].split("=")[0]]=
            decodeURIComponent(strs[i].split("=")[1]);
        }
    }
    return params;
}

tabbar菜单使用了不显示title属性,页面顶部使用了fixed,滚动时状态栏能看到滚动上去的内容处理:给状态栏也设置fixed,并添加个背景色。

<template>
	<!-- #ifdef APP-PLUS -->
	<view class="status-bar"></view>
	<!-- #endif -->
	
	<view class="nav">内容</view>
</template>
<style lang="scss" scoped>
.status-bar{
	height: var(--status-bar-height);
	position: fixed;
	width: 100%;
	top: 0;
	z-index: 9;
	background: #ffffff;
}
</style>

页面使用拖拽功能,并且拖拽不影响页面其它按钮点击等的操作
uniapp封装好了内置的拖拽组件movable-area**,要不影响页面其他操作可以使用 pointer-events 这个css属性,设置可拖动区域movable-area的pointer-events为none,可移动的视图容器movable-view的pointer-events为auto,既可以实现拖拽功能,又不影响页面其他操作,因为可拖动区域可能会覆盖页面其它内容:


<template>
<view class="container">
    <button type="primary">点击</button>
	<movable-area>
		<movable-view  direction="all" >text</movable-view>
	</movable-area>
</view>
</template>

<style lang="scss" scoped>
uni-movable-area{
		width: 100vw;
		height: calc(100vh - var(--status-bar-height));
		position: fixed !important;
		left: 0;
		top: var(--status-bar-height) ;
		pointer-events: none;
	}
	uni-movable-view{
		margin-left: calc(100vw - 380rpx);
		top: calc(100vh - var(--status-bar-height) - 260rpx);
		width: 380rpx;
		height: 260rpx;
		background: #a4a2a287;
		pointer-events: auto;
	}
</style>

其它知识累积

  1. 使用Hbuilder X创建的项目没有package.json文件,执行命令 npm init -y 创建,创建了后就可以通过 npm 安装依赖了。安装的插件引入方法:
import package from 'packageName'
const package = require('packageName')
  1. uview-ui在pages.json中配置时npm安装和下载安装2种引入方式不一样:npm安装的方式不需要前面的"@/“,下载安装的方式需要”@/"。
// npm安装方式引入
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
// 下载安装方式引入
 "^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
  1. @tab 在小程序不起作用;

  2. navigator需要在同级目录下跳转,不同级的目录需添加 open-type=“switchTab” 属性;

  3. uniapp微信小程序v-show不能和display:flex用在同一个元素上,flex的层级比v-show的display高,导致v-show无效,可以使用v-if

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐