移動H5頁面微信支付踩坑之旅(微信支付、單頁面路由模擬、按鈕加鎖、輪詢等常見功能)

蔓草發表於2018-06-18

開發背景:

.net混合開發的vue模板語法的單頁面應用,所以不存在腳手架以及沒有路由可以跳轉。

專案描述:

需要寫兩個頁面,在訂單詳情頁需要點選“請輸入手機號”進入手機號繫結頁面,手機號繫結成功後自動跳轉到訂單詳情頁,如果該手機號已經繫結成功,則不顯示“請輸入手機號”(即不可點選進入下一個頁面),只顯示該手機號。

專案思路:

在單頁面中使用v-show控制兩個頁面的切換,所以需要模擬真實兩個頁面的跳轉,即改變hash值並且監聽歷史條目變化。

一、監聽並且覆蓋微信的回退事件

當兩個頁面在同一路由下,從“手機號繫結”頁面點選微信的返回時不會進入“確認訂單”頁面,會直接返回,所以通過在url尾部新增可以識別的hash值並且使用方法進行監聽,以此判斷回到哪個頁面。

知識點儲備:

關於window.onpopstate事件其實是popstate事件在 window物件上的事件處理程式。每當處於啟用狀態的歷史記錄條目發生變化時,popstate事件就會在對應window物件上觸發.
因為給url加上了hash值雖然不會重新發出http請求但是會改變瀏覽器的訪問歷史。所以即使進入了“手機號繫結”頁面,popstate也能監聽到。

  1. 關於hash值
  2. 關於思路
  3. 關於js重新載入與重新整理
程式碼:

在“請輸入手機號”的點選事件中加上可以辨識的hash值

事件寫在methods中
複製程式碼
 inputPhoneNumber() {
        this.index = false;
        console.log("新增hash值");
        location.hash = "second";
        console.log("顯示繫結手機號的hash值");
        console.log(window.location);
},
複製程式碼
監聽事件寫在mouted鉤子函式中
複製程式碼
 mounted() {
        var url = window.location.href;
        window.onpopstate = function () {                 
            console.log("監聽回退事件");
            if (location.hash.indexOf("#second") > -1) {
                           
            } else {
                window.location.href = url;  
                }
            }
    }
複製程式碼

二、H5微信支付程式碼

思路:

1.在確認訂單頁面點選立即付款時,進行手機號是否繫結判斷,如果填寫手機號才可以進行下一步
2.呼叫介面向後臺傳送請求來拿去呼叫微信支付的引數(公眾號商戶付款的引數);
3.根據後臺返回的引數進行判斷,如果訂單未完成,就呼叫微信支付的內建介面,如果存在訂單,則跳轉到訂單完成頁面。
4.根據微信支付返回引數進行判斷,如果返回ok則呼叫後臺介面進行輪詢,查詢訂單是否完成。根據後臺狀態碼進行成功失敗的頁面跳轉。

程式碼:

付款按鈕:

toPayMoney() {
        console.log("觸發立即付款按鈕");
        var that = this;
        var returnUrl = location.href;
        that.disabled = true;
        if (!this.phone) {
            that.dialogVisible = true;
            that.infoMessage = "請先輸入手機號";
            console.log("確認訂單,手機號不存在時");
        } else {
            console.log("確認訂單,手機號存在時");
            that.selectParams();  //查詢引數
            console.log("確認訂單,手機號存在時,查詢支付引數");
        }
    },
複製程式碼

查詢支付的引數:

          selectParams() {
                        var that = this;
                        var returnUrl = location.href;
                          $.ajax({
                                url: '/api/wxpay/unifiedorder',
                                type: "GET",
                                cache: false,
                                dataType: 'json',
                                data: { number: this.number },
                                success: function (data) {
                                    if (data.code === 200) {
                                        if (data.data.isValid == true) {       
                                            return location.href = "/pay/subscription/" + @Model.SubscriptionID +"/finish?tradeNo=" + @Model.Number;
                                        } else {
                                            var json =data.data.jsParams;
                                            console.log("json" + (data.data.jsParams));
                                            //調起微信支付
                                            function onBridgeReady() {
                                                WeixinJSBridge.invoke(
                                                    'getBrandWCPayRequest', {
                                                        "appId": json["appId"],     //公眾號名稱,由商戶傳入
                                                        "timeStamp": json["timeStamp"],         //時間戳,自1970年以來的秒數
                                                        "nonceStr": json["nonceStr"], //隨機串
                                                        "package": json["package"],
                                                        "signType": json["signType"],         //微信簽名方式:
                                                        "paySign": json["paySign"] //微信簽名
                                                    },

                                                    function checkPayRes(res) {
                                                        console.log("請求後臺引數並且呼叫了微信支付");
                                                        //setInterval()
                                                        if (res.err_msg == "get_brand_wcpay_request:ok") {
                                                            that.polling();
                                                            // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在使用者支付成功後返回    ok,但並不保證它絕對可靠。
                                                        } else {

                                                        }
                                                    }
                                                );
                                            }

                                            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();
                                            }
                                        }
                                    } 
                                },
                                error: function (data) {
                                    console.log("呼叫後臺查詢訂單未成功");
                                }
                            })
                    },
複製程式碼

短輪詢的函式

  polling() {
                        var that = this;
                          $.ajax({
                                 url: '/api/wxpay/unifiedorder',
                                 type: "GET",
                                 cache: false,
                                 dataType: 'json',
                                 data: { number: this.number },
                                  success: function (data) {
                                      if (code.data === 100) {
                                            console.log("狀態碼101需要持續輪詢查詢");
                                              setInterval(that.polling(), 1000);
                                      } else if (code.data === 200) {
                                          clearInterval(that.polling());
                                          console.log("狀態碼200需要持續輪詢查詢");
                                          console.log("支付成功");
                                          location.href = "/pay/subscription/" + @Model.SubscriptionID +"/finish?tradeNo=" + @Model.Number;
                                            } else {
                                                  console.log(data.msg);
                                            }
                                     }
                          })
                   }
                 
複製程式碼

三、按鈕加鎖解鎖

其實上面的程式碼已經包括了部分加鎖與解鎖功能,下面寫一下思路:

  1. 使用button的 disabled屬性
  2. 使用v-bind給每個按鈕繫結變數。

相關文章