Vue2中實現微信分享支付功能

Vue2中實現微信分享支付功能

 

   近期作了一個微信公衆號先後分離項目,前端採用Vue2開發,後端SpringBoot,今天火燒眉毛的來給你們分享一下此次在開發中遇到的一些坑以及解決辦法。css

  在這裏,一些公衆號的基本配置我就很少說了,不懂的能夠看一下微信開發文檔。前端

  話很少說,我們開始吧!vue

 


 

安裝微信JS-SDK

 

  首先須要經過npm安裝微信的JS-SDKjava

 

npm -install weixin-js-sdk --save

  

  因爲項目是基於微信公衆號開發的,全部受權的時候微信會本身判斷用戶所用的瀏覽器是否爲微信瀏覽器,因此咱們這裏並無判斷用戶使用的是哪一種瀏覽器。webpack

 

封裝JS-SDK

  接着,新建一個jssdk.js,用來初始化微信JS-SDK。該方法接收一個對象參數,用於微信分享參數設置。由於微信簽名數據須要後端人員生成,因此須要使用axios來獲取這些數據。而後前端調用wx.config方法完成配置,這裏須要注ios

意的地方有幾點:git

 

  1. SPA單頁面應用,url都有攜帶#,經過url獲取config配置簽名時,截取#號以前的數據看成入參。
  2. wx.config入參中的jsApiList必定要配置你用到的微信JS方法。
  3. 微信js-sdk-1.4.0廢棄以前的「onMenuShareTimeline」,「onMenuShareAppMessage」,「onMenuShareQQ」,取代它們的是「updateAppMessageShareData」,「updateTimelineShareData」。詳情見:微信開發文檔

 

初始化微信JS-SDK

 

  因爲每一個頁面的分享內容不通,每次跳轉頁面的時候都須要從新調用wx.config配置分享內容,因此我使用router的全局後置鉤子touter.afterEach,分享參數經過路由中的meta獲取,你也能夠經過接口的形式配置。web

 

實現代碼

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
}

  

  咱們項目中只使用到了分享,支付,地圖功能,到這裏微信分享就開發好了,須要注意幾點:vue-router

 

  1. 微信JS判斷支付成功,使用 res.errMsg === 'chooseWXPay:ok' 判斷,微信JS取消支付/支付失敗不是在success回調函數中判斷,而是經過cancel回調函數和fail回調函數判斷。
  2. 地圖經緯度必定不要寫反。嘿嘿嘿!

 

微信支付

   咱們將封裝好的jssdk.js放入全局vue中,這樣使用起來方便。在main.js中引入jssdk.js,再將jssdk拋出的對象放入全局變量中。npm

  支付以前,須要調用後端接口完成統一下單,下單成功以後才能夠調用微信支付,話很少說,直接上代碼了。

// 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開發的我,只能給你們分享這麼多了,不喜勿噴,謝謝各位大神 !!!

相關文章
相關標籤/搜索