在 UniApp 中使用Mixins混合方法实现微信支付与支付宝支付
目录
前言
在
UniAp
中集成支付功能时,我们经常需要根据不同的支付方式(如微信支付、支付宝支付)进行不同的处理。为了避免代码冗余和提升代码的可维护性,可以使用Vue
的Mixins
技术 将支付逻辑提取到单独的混合文件中,在需要的地方复用。这不仅提高了代码的可重用性,还能够帮助我们更加清晰地组织代码结构。本文将详细解释如何在UniApp
中使用Vue Mixins
技术来处理微信支付和支付宝支付的逻辑,并结合实际代码进行说明。
项目概述
本项目展示了如何在 UniApp
中集成 微信支付 和 支付宝支付。根据不同的平台和支付方式,代码会根据选择的支付渠道来进行相应的请求和处理。
功能概述:
根据支付方式(支付宝或微信支付)展示不同的支付流程。
支付过程中包括获取订单信息、请求支付、支付成功或失败的回调处理。
代码解析
data() 数据定义
在 data
中定义了以下几个属性:
provider:
支付方式,默认设置为'alipay'
,即初始使用支付宝支付。根据需求,可以动态切换为微信支付。loading:
用于标识支付是否正在进行中。避免用户在支付过程中多次点击支付按钮。data:
存储请求支付接口所需要的订单信息。
data() {
return {
provider: 'alipay', // 支付方式, 即提供商
loading: false, // 是否提交中
data: {}, // 订单信息服务接口请求参数
}
}
onLoad() 页面加载时的支付方式选择
在 onLoad
方法中,根据平台的不同,设置支付方式。在微信小程序(MP-WEIXIN)
中,支付方式会自动切换为微信支付(wxpay)
。
onLoad(option) {
// #ifdef MP-WEIXIN
// 微信小程序选中微信支付
this.provider = 'wxpay'
// #endif
}
payChange() 支付方式选择
用户可以通过界面选择支付方式(支付宝或微信支付)。payChange
方法会根据用户的选择更新 provider
的值。
payChange(e) {
this.provider = e.detail.value
}
payHandler() 支付处理逻辑
payHandler
方法用于执行支付逻辑:
- 首先,设置
loading
为true
,表示支付操作正在进行中。- 获取订单信息(通过
getOrderInfo()
方法)。- 根据支付渠道
(provider)
调用uni.requestPayment()
,这是UniApp
提供的支付接口,用于发起支付请求。- 支付成功或失败时,分别触发
success
和fail
回调。- 完成支付后,返回订单页面并显示支付成功的提示。
async payHandler() {
// 支付中
this.loading = true
// #ifdef APP-PLUS
let orderInfo = await this.getOrderInfo();
if (!orderInfo) {
uni.showModal({
content: '获取支付信息失败',
showCancel: false
})
return
}
uni.requestPayment({
provider: this.provider,
orderInfo: orderInfo,
success: (e) => {
console.log("success", e);
uni.showToast({
title: "支付成功!"
})
this.navTo('/pages/order/order')
},
fail: (e) => {
console.log("fail", e);
uni.showModal({
content: "支付失败,请重试。",
showCancel: false
})
},
complete: () => {
this.loading = false;
}
})
// #endif
}
getOrderInfo() 获取订单信息
getOrderInfo()
方法用于从后端获取支付订单信息:
- 如果 openid 存在(即微信小程序支付),则直接返回模拟的订单信息。
- 否则,根据选择的支付方式(支付宝或微信支付),调用对应的 API获取订单信息。
- 如果成功返回订单信息,调用 resolve(),否则返回错误。
getOrderInfo(openid) {
return new Promise(async (resolve, reject) => {
if (openid) {
let orderInfo = {
"timeStamp": "1414561699",
"nonceStr": "5K8264ILTKCH16CQ2502SI8ZNMTM67VS",
"package": "prepay_id=wx201410272009395522657a690389285100",
"paySign": "oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7vaRvkYD7rthRAZ"
}
resolve(orderInfo)
return
}
let res = null
if (this.provider === 'alipay') {
res = await api.getOrderInfoAlipay(this.data)
} else if (this.provider === 'wxpay') {
res = await api.getOrderInfoWxpay(this.data)
}
if (res && res.code === 20000) {
resolve(res.data)
} else {
reject(new Error('获取支付信息失败' + res.message))
}
})
}
wxPayHandler() 微信支付流程
wxPayHandler()
方法主要用于微信小程序支付:
- 获取用户的
openid
,如果没有存储在本地,调用loginWeixinMp()
方法进行微信登录。- 根据
openid
获取订单信息。- 调用
uni.requestPayment()
发起微信支付请求。- 支付完成后处理结果,展示支付成功或失败的提示。
async wxPayHandler() {
this.loading = true
let openid = uni.getStorageSync('openid')
if (!openid) {
try {
openid = await this.loginWeixinMp()
} catch (e) {
console.error(e)
}
if (!openid) {
uni.showModal({
content: '获取openid失败',
showCancel: false
})
this.loading = false
return
}
}
let orderInfo = await this.getOrderInfo(openid)
uni.requestPayment({
...orderInfo,
success: (res) => {
uni.showToast({
title: "支付成功!"
})
},
fail: (res) => {
uni.showModal({
content: "支付失败, 原因: " + res.errMsg,
showCancel: false
})
},
complete: () => {
this.loading = false;
}
})
}
loginWeixinMp() 微信小程序登录获取 openid
oginWeixinMp()
方法用于在微信小程序中获取 openid
:
- 使用
uni.login()
获取微信登录的code
。- 通过后端接口请求获取
openid
并存储在本地。
loginWeixinMp() {
return new Promise((resolve, reject) => {
uni.login({
provider: 'weixin',
success: (res) => {
const code = res.code
let openid = 'xx' // 获取openid的请求
uni.setStorageSync('openid', openid)
resolve(openid)
},
fail(err) {
reject(err)
}
})
})
}
微信支付与支付宝支付步骤总结
微信支付:
- 获取用户的 openid(用于标识用户身份)。
- 通过 openid 向后端请求订单信息。
- 调用 uni.requestPayment() 发起支付请求。
- 支付完成后,展示支付结果并处理回调。
支付宝支付:
- 选择支付宝作为支付渠道。
- 向后端请求订单信息。
- 调用 uni.requestPayment() 发起支付请求。
- 支付完成后,展示支付结果并处理回调。
总结
通过本项目,我们可以清晰地看到如何在 UniApp 中实现微信支付和支付宝支付。UniApp 提供了跨平台的支持,可以通过不同的平台条件来切换支付方式,并根据支付的结果给用户反馈。开发者可以在此基础上扩展更多支付功能,比如支付日志、订单查询等。
全部代码
订单支付页面代码
<template>
<view>
<view class="card option-pay">
<view class="title">支付方式</view>
<radio-group @change="payChange">
<!-- #ifndef MP-WEIXIN -->
<label class="pay-item center space-between">
<view class="left center">
<image src="/static/pay/alipay.png"></image>
<text>支付宝</text>
</view>
<radio value="alipay" :checked="provider==='alipay'" style="transform:scale(0.8)" />
</label>
<!-- #endif -->
<!-- #ifndef MP-ALIPAY -->
<label class="pay-item center space-between">
<view class="left center">
<image src="/static/pay/wxpay.png"></image>
<text>微信支付</text>
</view>
<radio value="wxpay" :checked="provider==='wxpay'" style="transform:scale(0.8)" />
</label>
<!-- #endif -->
</radio-group>
</view>
<view class="card price space-between">
<text>实付金额</text>
<text>¥{{data.price}}</text>
</view>
<!-- #ifdef MP-WEIXIN -->
<button class="btn" :loading="loading" :disabled="loading" @click="wxPayHandler">立即支付</button>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<button class="btn" :loading="loading" :disabled="loading" @click="payHandler">立即支付</button>
<!-- #endif -->
</view>
</template>
<script>
import payMixin from './mixins/pay.js'
export default {
mixins: [payMixin],
data() {
return {
// provider: 'alipay', // 支付方式,即提供商
// data: {}
}
},
onLoad(option) {
//获取支付数据
if (option.params) {
this.data = JSON.parse(option.params)
}
},
methods: {
// payChange() {}
}
}
</script>
<style lang="scss">
.card {
margin: 0 30rpx;
padding: 0 20rpx;
background-color: #FFF;
margin-top: 30rpx;
border-radius: 20rpx;
box-shadow: 1px 0 5px 0 rgba(0, 0, 0, 0.08);
}
.option-pay {
.title {
font-size: 35rpx;
line-height: 90rpx;
border-bottom: $wyk-underline;
}
.pay-item {
line-height: 90rpx;
.left {
image {
width: 60rpx;
height: 60rpx;
}
text {
font-size: 33rpx;
padding-left: 20rpx;
}
}
}
}
.price {
font-size: 30rpx;
line-height: 90rpx;
border-bottom: 1px solid #F8F9FB;
text:last-child {
color: $mxg-text-color-red;
}
}
.btn {
margin: 60rpx 30rpx;
background-color: $mxg-color-primary;
color: #fff;
line-height: 80rpx;
font-size: 30rpx;
&::after {
// 加载中时,隐藏边框
border: none;
}
}
</style>
mixins混合pay.js代码
import api from '@/api/order.js'
export default {
data() {
return {
provider: 'alipay', // 支付方式,即提供商
loading: false, // 是否提交中
data: {}, //订单信息服务接口请求参数
}
},
onLoad(option) {
// #ifdef MP-WEIXIN
// 微信小程序选中微信支付
this.provider = 'wxpay'
// #endif
},
methods: {
// 选择支付方式
payChange(e) {
this.provider = e.detail.value
},
// 微信支付、支付宝操作
async payHandler() {
// 支付中
this.loading = true
// #ifdef APP-PLUS
// 1. 发送请求到服务端,服务端生成订单信息,响应预支付订单号
let orderInfo = await this.getOrderInfo();
if (!orderInfo) {
uni.showModal({
content: '获取支付信息失败',
showCancel: false
})
return
}
// 2. 请求支付
uni.requestPayment({
provider: this.provider, // 支付渠道
orderInfo: orderInfo,
success: (e) => {
console.log("success", e);
uni.showToast({
title: "支付成功!"
})
// 回到订单页面
this.navTo('/pages/order/order')
},
fail: (e) => {
console.log("fail", e);
uni.showModal({
content: "支付失败,请重试。",
showCancel: false
})
},
complete: () => {
this.loading = false;
}
})
// #endif
},
// 获取订单信息 (微信小程序支付需要openid)
getOrderInfo(openid) {
// 不要少了async
return new Promise(async (resolve, reject) => {
if (openid) {
// 微信小程序支付, 发送请求到服务器获取订单信息,参考:https: //pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_2.shtml
let orderInfo = {
"timeStamp": "1414561699",
"nonceStr": "5K8264ILTKCH16CQ2502SI8ZNMTM67VS",
"package": "prepay_id=wx201410272009395522657a690389285100", //预支付交易会话标识( prepay_id) "signType": "RSA",
"paySign": "oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7vaRvkYD7rthRAZ\/X+QBhcCYL21N7cHCTUxbQ+EAt6Uy+lwSN22f5YZvI45MLko8Pfso0jm46v5hqcVwrk6uddkGuT + Cdvu4WBqDzaDjnNa5UK3GfE1Wfl2gHxIIY5lLdUgWFts17D4WuolLLkiFZV + JSHMvH7eaLdT9N5GBovBwu5yYKUR7skR8Fu + LozcSqQixnlEZUfyE55feLOQTUYzLmR9pNtPbPsu6WVhbNHMS3Ss2 + AehHvz + n64GDmXxbX++IOBvm2olHu3PsOUGRwhudhVf7UcGcunXt8cqNjKNqZLhLw4jq\ / xDg == ",
}
resolve(orderInfo)
return
}
let res = null
console.log('订单信息请求参数:', this.data)
if (this.provider === 'alipay') {
res = await api.getOrderInfoAlipay(this.data)
} else if (this.provider === 'wxpay') {
res = await api.getOrderInfoWxpay(this.data)
}
if (res && res.code === 20000) {
resolve(res.data)
} else {
reject(new Error('获取支付信息失败' + res.message))
}
})
},
// 微信小程序支付
async wxPayHandler() {
this.loading = true
// 1. 先获取用户code, 再获取openid
let openid = uni.getStorageSync('openid')
if (!openid) {
try {
openid = await this.loginWeixinMp()
} catch (e) {
console.error(e)
}
if (!openid) {
uni.showModal({
content: '获取openid失败',
showCancel: false
})
this.loading = false
return
}
}
// 2. 通过 openid 再获取订单信息,
let orderInfo = await this.getOrderInfo(openid)
// 3. 通过订单预支付信息,去调用支付接口
uni.requestPayment({
...orderInfo,
success: (res) => {
uni.showToast({
title: "支付成功!"
})
},
fail: (res) => {
uni.showModal({
content: "支付失败,原因为: " + res.errMsg,
showCancel: false
})
},
complete: () => {
this.loading = false;
}
})
},
// 登录微信小程序
loginWeixinMp() {
// 微信小程序登录参考:
https: //developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
return new Promise((resolve, reject) => {
// 1. 先使用微信登录小程序响应 code,
uni.login({
provider: 'weixin',
success: (res) => {
console.log('登录', res)
const code = res.code
// 2. 请求服务端通过code获取openid
let openid = 'xx'
uni.setStorageSync('openid', openid)
resolve(openid)
},
fail(err) {
reject(err)
}
})
})
},
}
}
实现效果
由于商品信息都是mock
数据,code
之类的也都是mock
数据,所以导致失败,但是都可以调起微信支付和支付宝支付,打开微信和支付宝即为付款界面。