Vue2中实现微信分享支付功能
Vue2中实现微信分享支付功能
近期做了一个微信公众号前后分离项目,前端采用Vue2开发,后端SpringBoot,今天迫不及待的来给大家分享一下这次在开发中遇到的一些坑以及解决办法。
在这里,一些公众号的基本配置我就不多说了,不懂的可以看一下微信开发文档。
话不多说,咱们开始吧!
安装微信JS-SDK
首先需要通过npm安装微信的JS-SDK
npm -install weixin-js-sdk --save
由于项目是基于微信公众号开发的,所有授权的时候微信会自己判断用户所用的浏览器是否为微信浏览器,所以我们这里并没有判断用户使用的是哪种浏览器。
封装JS-SDK
接着,新建一个jssdk.js,用来初始化微信JS-SDK。该方法接收一个对象参数,用于微信分享参数设置。因为微信签名数据需要后端人员生成,所以需要使用axios来获取这些数据。然后前端调用wx.config方法完成配置,这里需要注
意的地方有几点:
- SPA单页面应用,url都有携带#,通过url获取config配置签名时,截取#号之前的数据当作入参。
- wx.config入参中的jsApiList一定要配置你用到的微信JS方法。
- 微信js-sdk-1.4.0废弃之前的“onMenuShareTimeline”,“onMenuShareAppMessage”,“onMenuShareQQ”,取代它们的是“updateAppMessageShareData”,“updateTimelineShareData”。详情见:微信开发文档
初始化微信JS-SDK
由于每个页面的分享内容不通,每次跳转页面的时候都需要重新调用wx.config配置分享内容,所以我使用router的全局后置钩子touter.afterEach,分享参数通过路由中的meta获取,你也可以通过接口的形式配置。
实现代码
router路由index.js
import Vue from 'vue'
import Router from 'vue-router'
import CourseDetail from '@/components/CourseDetail'
import StudyAbroad from '@/article/StudyAbroad'
import MuseumIndustry from '@/article/MuseumIndustry'
import WeekendCamp from '@/article/WeekendCamp'
import ColdSummerCamp from '@/article/ColdSummerCamp'
import Login from '@/login/Login'
import Member from '@/member/Member'
import RechargeRecord from '@/member/RechargeRecord'
import CustomerService from '@/member/CustomerService'
import FeedBack from '@/member/FeedBack'
import NearFuture from '@/future/NearFuture'
import PersonalData from '@/member/PersonalData'
import RechargeDetails from '@/member/RechargeDetails'
import RechargeSuccess from '@/member/RechargeSuccess'
import RechargeFile from '@/member/RechargeFile'
import Payment from '@/member/Payment'
import Invalid from '@/member/Invalid'
import ResultAlready from '@/member/ResultAlready'
import NotStarted from '@/member/NotStarted'
import ClassList from '@/components/Classlist'
import Fillinformation from '@/components/Fillinformation/Fillinformation'
import SignupDetail from '@/components/SignupDetail/SignupDetail'
import WxFail from '@/components/result/WxFail'
import CourseFail from '@/components/result/CourseFail'
import SignupSuccess from '@/components/result/SignupSuccess'
import SignupFail from '@/components/result/SignupFail'
import Ditu from '@/components/Ditu'
import Author from '@/author/Author'
import DelToken from '@/member/DelToken'
import wx from '@/wx/jssdk'
import global from '@/global/global' Vue.use(Router) let router = new Router({
// mode: 'history', // 把Router的mode修改为history模式,VueRouter默认的模式为HASH模式
routes: [
{
path: '/CourseDetail/:courseId',
name: 'CourseDetail',
component: CourseDetail,
meta: {
title: '课程详情',
type: true,
shareInfo: {
title: '知育童行',
desc: '打造丰富多彩的亲子活动,帮助家长们给孩子更全面的素质教育。',
imgUrl: global.WX_STATIC_URL + '/images/share/share.png'
}
},
props: true
},
{
path: '/StudyAbroad',
name: 'StudyAbroad',
component: StudyAbroad,
meta: {
title: '微留学',
type: false
}
},
{
path: '/MuseumIndustry',
name: 'MuseumIndustry',
component: MuseumIndustry,
meta: {
title: '博物行',
type: false
}
},
{
path: '/WeekendCamp',
name: 'WeekendCamp',
component: WeekendCamp,
meta: {
title: '周末营地',
type: false
}
},
{
path: '/author',
name: 'Author',
component: Author,
meta: {
title: '授权中',
type: false
}
},
{
path: '/DelToken',
name: 'DelToken',
component: DelToken,
meta: {
title: '删除缓存',
type: false
}
}
],
scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
return { x: 0, y: 0 }
}
}
}) // 全局守卫,微信授权
router.beforeEach((to, from, next) => {
// 路由发生变化修改页面title
if (to.meta.title) {
document.title = to.meta.title
}
if (process.env.NODE_ENV !== 'development') {
const token = window.localStorage.getItem('token')
if (token) {
if (to.path === '/author') {
next({
path: '/'
})
} else {
next()
}
} else {
if (to.path !== '/author') {
// 保存用户进入的url
window.localStorage.setItem('authUrl', to.fullPath)
// 跳转到微信授权页面
window.location.href = process.env.BASE_URL + '/wx/OAuth2/index'
} else {
next()
}
}
} else {
window.localStorage.setItem('token', 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJvUUFFYndSSU5VVlhPLVZoOWhEcDUzX3RNeEgwIn0.eShRG4fVFFv4w2gHnkyh7QDdVpG1meOHSZXOrbq-psE')
}
next()
}) router.afterEach((to, from) => {
// 微信JSSDK统一处理
wx.init({
title: to.meta.type ? to.meta.shareInfo.title : '',
desc: to.meta.type ? to.meta.shareInfo.desc : '',
link: global.SHARE_URL + '/#' + to.path,
imgUrl: to.meta.type ? to.meta.shareInfo.imgUrl : '',
type: to.meta.type
})
}) export default router
jssdk.js
import wx from 'weixin-js-sdk'
import axios from '@/utils/request'
import app from '@/main'
const jsApiList = ['updateAppMessageShareData', 'updateTimelineShareData', 'chooseImage', 'hideAllNonBaseMenuItem', 'showAllNonBaseMenuItem', 'chooseWXPay', 'openLocation'] /**
* 微信分享配置
* @param url 分享Url
* @param isShowShareMenu true:显示分享菜单 false:禁用
*/
function init (shareBean) {
axios.post('/wx/config/getJsApiSignature', {
url: window.location.href.split('#')[0]
}).then(function (response) {
let data = response.data
wx.config({
debug: false,
appId: data.appId, // 和获取Ticke的必须一样------必填,公众号的唯一标识
timestamp: data.timestamp, // 必填,生成签名的时间戳
nonceStr: data.nonceStr, // 必填,生成签名的随机串
signature: data.signature, // 必填,签名,见附录1
// 需要分享的列表项:发送给朋友,分享到朋友圈,分享到QQ,分享到QQ空间
jsApiList: jsApiList
})
// 处理验证失败的信息
wx.error(function (res) {
console.error('验证失败返回的信息')
})
// 处理验证成功的信息
wx.ready(function () {
// 自定义“分享给朋友”及“分享到QQ”按钮的分享内容(1.4.0)
if (shareBean.type) {
wx.updateAppMessageShareData({
title: shareBean.title, // 分享标题
desc: shareBean.desc, // 分享描述
link: shareBean.link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: shareBean.imgUrl, // 'http://cicstatic.thjinrong.com/static/images/ClassicsList/share/chinese.png', // 分享图标
success: function () {
// 用户确认分享后执行的回调函数
console.info('分享成功')
}
})
// 自定义“分享到朋友圈”及“分享到QQ空间”按钮的分享内容(1.4.0)
wx.updateTimelineShareData({
title: shareBean.title, // 分享标题
link: shareBean.link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: shareBean.imgUrl, // 分享图标
success: function () {
// 设置成功
console.info('分享成功')
}
})
}
// 隐藏所有非基础按钮接口
if (!shareBean.type) {
wx.hideAllNonBaseMenuItem()
} else {
wx.showAllNonBaseMenuItem()
}
})
})
} /**
* 上传图片
*/
function chooseImage () {
wx.chooseImage({
count: 1, // 默认9
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success: function (res) {
// let localIds = res.localIds // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
wx.getLocalImgData({
localId: res.localIds[0], // 图片的localID
success: function (res) {
// localData是图片的base64数据,可以用img标签显示
// store.dispatch('setLocalId', res.localData)
}
})
}
})
} /**
* 支付
*/
function pay (data) {
wx.chooseWXPay({
timestamp: data.data.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
nonceStr: data.data.nonceStr, // 支付签名随机串,不长于 32 位
package: data.data.packageValue, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
signType: data.data.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
paySign: data.data.paySign, // 支付签名
outTradeNo: data.data.outTradeNo, // 商户订单号
success: function (res) {
// 支付成功后的回调函数
console.info(res)
if (res.errMsg === 'chooseWXPay:ok') {
// 使用以上方式判断前端返回,微信团队郑重提示 :
// res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
// app.$store.dispatch('updateStatus', true)
console.info('支付成功')
} else {
app.$store.dispatch('updateStatus', false)
console.info('支付失败')
}
},
// 支付取消回调函数
cancel: function (res) {
app.$store.dispatch('updateStatus', false)
console.info('取消支付')
},
// 支付失败回调函数
fail: function (res) {
app.$store.dispatch('updateStatus', false)
console.info('支付失败')
}
})
} /**
* 地图
* @param 纬度
* @param 经度
*/
function map (params) {
wx.openLocation({
latitude: params.latitude, // 纬度,浮点数,范围为90 ~ -90
longitude: params.longitude, // 经度,浮点数,范围为180 ~ -180
name: params.name, // 位置名
address: params.address, // 地址详情说明
scale: params.scale, // 地图缩放级别,整形值,范围从1~28。默认为最大
infoUrl: params.infoUrl // 在查看位置界面底部显示的超链接,可点击跳转
})
} export default {
init: init,
chooseImage: chooseImage,
pay: pay,
map: map
}
我们项目中只使用到了分享,支付,地图功能,到这里微信分享就开发好了,需要注意几点:
- 微信JS判断支付成功,使用 res.errMsg === 'chooseWXPay:ok' 判断,微信JS取消支付/支付失败不是在success回调函数中判断,而是通过cancel回调函数和fail回调函数判断。
- 地图经纬度一定不要写反。嘿嘿嘿!
微信支付
我们将封装好的jssdk.js放入全局vue中,这样使用起来方便。在main.js中引入jssdk.js,再将jssdk抛出的对象放入全局变量中。
支付之前,需要调用后端接口完成统一下单,下单成功之后才可以调用微信支付,话不多说,直接上代码了。
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import './assets/css/reset.css'
import './assets/js/font'
import axios from '@/utils/request.js'
import wx from '@/wx/jssdk'
import VConsole from 'vconsole'
import global from '@/global/global'
import store from '@/store/index'
// 全局处理错误提示、数据加载
import {ToastPlugin, LoadingPlugin} from 'vux'
Vue.use(ToastPlugin)
Vue.use(LoadingPlugin) // VConsole加载
process.env.NODE_ENV === 'test' && Vue.use(new VConsole()) // import 'element-ui/lib/theme-chalk/index.css'
Vue.config.productionTip = false
Vue.prototype.axios = axios
Vue.prototype.globalParams = global // 加载mock模块
process.env.NODE_ENV === 'mock' && require('@/mock/login')
process.env.NODE_ENV === 'mock' && require('@/mock/classList')
process.env.NODE_ENV === 'mock' && require('@/mock/courseDetail')
process.env.NODE_ENV === 'mock' && require('@/mock/fillinformation')
process.env.NODE_ENV === 'mock' && require('@/mock/signupDetail') // 引入工具集
Vue.prototype.toolkit = require('@/utils/toolkit')
// 微信JSSDK
Vue.prototype.wx = wx /* eslint-disable no-new */
const app = new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
}) export default app
调用微信支付
// 微信支付
weChatPayment (orderId) {
let _this = this
this.axios.post('/wx/pay/act', {
orderId: orderId,
body: 'Demo-充值',
}).then(function (res) {
let data = res.data
if (data.code === 1) {
// 统一下单返回参数
_this.wx.pay(data)
} else if (data.code === 0) {
console.info('统一支付下单失败')
_this.$store.dispatch('updateStatus', false)
}
})
},
作为java开发的我,只能给大家分享这么多了,不喜勿喷,谢谢各位大神 !!!
Vue2中实现微信分享支付功能的更多相关文章
- 不接入微信sdk,在APP中实现微信分享,支付
前段时间在很多地方接入了微信的sdk,发现过程比较繁琐,此外因为导入的sdk比较大会影响最终APP打包的体积,所以就有了不接入sdk也实现相同的功能的想法. 要实现这个目标我个人认为最困难的地方是不知 ...
- vue项目中关于微信分享的坑,以及安卓和ios获取location.href不同的处理
最近做vue项目的微信公众号项目,涉及到微信分享,记录一下心得,以备后用,vue路由用的是hash模式: 该项目只是公众号里面的h5链接,不需要获取code获取access_token的票据,因此前端 ...
- app中使用微信分享注意事项
1. 在微信公众平台开通一个微信公众号,https://mp.weixin.qq.com 2. 将自己制作好的已签名的app安装到手机上 3. 下载微信开放平台获取应用签名的apk--- gen ...
- android APP 中微信分享功能实现 的总结
//花了很长时间最终完成了微信分享功能,中间走了很多弯路,在此做一下小结,希望对在应用中使用到微信分享的朋友有所帮助. 主要问题就是下面两个: 1.为什么运行了项目之后,微信分享只是闪了一下就没有了? ...
- AndroidStudio用微信官方方法接入微信分享功能
转载请注明出处:http://www.cnblogs.com/wangoublog/p/5367950.html 现在微信的功能众所周知,用户量.影响力也是惊人,很多应用接入微信的功能已成为一种不可缺 ...
- Vue+Vue-router微信分享功能
在使用vue和vue-router路由框架已经开发过好几个项目了,其中也遇到不少坑,有些坑各种搜也没有找到非常理想的答案. vue学习相对来说还是比较简单,官方文档说明非常清楚(https://cn. ...
- AndroidStudio怎么实现微信分享功能
在应用中添加微信分享功能,需要在微信开放平台上传你的应用,审核通过后方可使用此功能. https://open.weixin.qq.com/网址 申请的过程比较简单,这里就不追溯了,贴一个友情链接 h ...
- VueJs单页应用实现微信网页授权及微信分享功能
在实际开发中,无论是做PC端.WebApp端还是微信公众号等类型的项目的时候,或多或少都会涉及到微信相关的开发,最近公司项目要求实现微信网页授权,并获取微信用户基本信息的功能及微信分享的功能,现在总算 ...
- 如何在ios中集成微信登录功能
在ios中集成微信的登录功能有两种方法 1 用微信原生的api来做,这样做的好处就是轻量级,程序负重小,在Build Settings 中这样设置 然后设置 友盟的设置同上,但是要注意,加入你需要的所 ...
随机推荐
- STM32 ~ USART接收不定长数据
IDLE中断什么时候发生? IDLE就是串口收到一帧数据后,发生的中断.什么是一帧数据呢?比如说给单片机一次发来1个字节,或者一次发来8个字节,这些一次发来的数据,就称为一帧数据,也可以叫做一包数据. ...
- ruby 字符串
字符串处理函数 1.返回字符串的长度 str.length => integer 2.判断字符串中是否包含另一个串 str.include? other_str => true or fa ...
- POJ - 3984 迷宫问题 【BFS】
题目链接 http://poj.org/problem?id=3984 思路 因为要找最短路 用BFS 而且 每一次 往下一层搜 要记录当前状态 之前走的步的坐标 最后 找到最短路后 输出坐标就可以了 ...
- IIS 7.5 虚拟主机独立用户的配置.
1:新建用户 2:打开 IIS->功能视图->打开编辑身份验证->匿名身份验证,点右边编辑->匿名用户标识中选"特定用户"->确定. 3:编缉网站的权 ...
- SpringBoot2.0之整合Dubbo
Dubbo支持协议 Dubbo支持dubbo.rmi.hessian.http.webservice.thrift.redis等多种协议,但是Dubbo官网是推荐我们使用Dubbo协议的. Sprin ...
- oracle_sql的用法?
本机连接oracle 数据库?打开cmd ----> 不同的用户有不同的用户名密码 ----> sqlplus scott/tiger(安装oracle数据库预留的用户)---- 回车 - ...
- ARP之windows下的ARP命令
ARP之windows下的ARP命令 arp -a 查看当前电脑上的ARP映射表.可以看到当前的ARP的映射关系是动态的还是静态的. arp -s w.x.y.z aa-bb-cc-dd-ee-ff ...
- display:inline-bock的注意
前端当一组元素设置为display:inline-block;时,每个元素之间的回车会被作为一个空格.
- hadoop源码剖析--hdfs安全模式
一.什么是安全模式 hadoop安全模式是name node的一种状态,处于该状态时有种量特性: 1.namenode不接受任何对hfds文件系统的改变操作(即此时整个文件系统处于只读状态): 2.不 ...
- ACM学习历程—SNNUOJ 1110 传输网络((并查集 && 离线) || (线段树 && 时间戳))(2015陕西省大学生程序设计竞赛D题)
Description Byteland国家的网络单向传输系统可以被看成是以首都 Bytetown为中心的有向树,一开始只有Bytetown建有基站,所有其他城市的信号都是从Bytetown传输过来的 ...