在前面隨筆《利用微信公眾號實現商品的展示和支付(1)》介紹了商品的列表和明細信息的處理,本篇隨筆接著上一篇,繼續介紹關於商品的微信支付和購物車處理方面,其中微信支付裡面,也涉及到了獲取微信共用地址的處理,從而個更加方便錄入郵寄地址信息;購物車可以從本地的localStorage對象進行獲取和處理,也... ...
在前面隨筆《利用微信公眾號實現商品的展示和支付(1)》介紹了商品的列表和明細信息的處理,本篇隨筆接著上一篇,繼續介紹關於商品的微信支付和購物車處理方面,其中微信支付裡面,也涉及到了獲取微信共用地址的處理,從而個更加方便錄入郵寄地址信息;購物車可以從本地的localStorage對象進行獲取和處理,也可通過介面獲取資料庫記錄的購物車信息,本案例介紹通過localStorage進行購物車處理方式。
1、商品的微信支付處理
商品的微信支付處理,其中涉及了兩個場景,一個是直接購買,一個是通過購物車的結算方式,兩個處理界面有所差異,直接付款購買的界面是對當前選中商品進行單項的結算處理,預設數量為1;而購物車訂單結算則是利用購物車的記錄進行微信支付的處理,購物車可以從本地的localStorage對象進行獲取和處理,也可通過介面獲取資料庫記錄的購物車信息,本案例介紹通過localStorage進行購物車處理方式。
對選中商品直接結算界面如下所示。
購物車結算界面如下所示。
先來看看微信共用地址的處理界面,代碼如下所示。
<!--配送地址處理--> <div class="weui-panel"> <div class="weui-panel__bd"> <div class="weui-media-box weui-media-box_small-appmsg"> <div class="weui-cells"> <div class="weui-cell weui-cell_access"> <div class="weui-cell__bd weui-cell_primary"> <p class="font-14"><span class="mg-r-10">配送地址</span><span class="fr"><a onclick="GetAddress()" class="weui-btn_mini weui-btn_primary">獲取微信地址</a></span></p> </div> </div> </div> </div> </div> </div> <div class="wy-media-box weui-media-box_text address-select"> <div class="weui-media-box_appmsg"> <div class="weui-media-box__hd proinfo-txt-l" style="width:20px;"><span class="promotion-label-tit"><img src="~/Content/wechat/web/images/icon_nav_city.png" /></span></div> <div class="weui-media-box__bd"> <a href="/h5/address" class="weui-cell_access"> <h4 class="address-name"></h4> <div class="address-txt"></div> </a> </div> <div class="weui-media-box__hd proinfo-txt-l" style="width:16px;"><div class="weui-cell_access"><span class="weui-cell__ft"></span></div></div> </div> </div>
獲取微信共用地址,需要配合微信的JSSDK的JS代碼進行處理,如下是處理的代碼。
<script language="javascript"> var appid = '@ViewBag.appid'; var noncestr = '@ViewBag.noncestr'; var signature = '@ViewBag.signature'; var timestamp = '@ViewBag.timestamp'; wx.config({ debug: false, appId: appid, // 必填,公眾號的唯一標識 timestamp: timestamp, // 必填,生成簽名的時間戳 nonceStr: noncestr, // 必填,生成簽名的隨機串 signature: signature, // 必填,簽名,見附錄1 jsApiList: [ 'checkJsApi', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'getLocalImgData', 'openAddress' ] }); //所有準備好後 wx.ready(function () { }); //獲取微信共用地址 function GetAddress() { wx.openAddress({ success: function (res) { var userName = res.userName; // 收貨人姓名 var postalCode = res.postalCode; // 郵編 var provinceName = res.provinceName; // 國標收貨地址第一級地址(省) var cityName = res.cityName; // 國標收貨地址第二級地址(市) var countryName = res.countryName; // 國標收貨地址第三級地址(國家) var detailInfo = res.detailInfo; // 詳細收貨地址信息 var nationalCode = res.nationalCode; // 收貨地址國家碼 var telNumber = res.telNumber; // 收貨人手機號碼 //$.alert(`${detailInfo}`); $(".address-name").html(`<span>${userName}</span><span>${telNumber}</span>`); $(".address-txt").text(`${detailInfo}`); } }); } </script>
而直接購買的產品信息,就是通過ID獲取對應商品信息,綁定在控制項上即可,如下界面代碼所示。
<!--購買商品信息--> <div class="wy-media-box weui-media-box_text"> <div class="weui-media-box__bd"> <div class="weui-media-box_appmsg ord-pro-list"> <div class="weui-media-box__hd"><a href="pro_info.html"><img id="productimg" class="weui-media-box__thumb" src="" alt=""></a></div> <div class="weui-media-box__bd"> <h1 class="weui-media-box__desc"><a href="/h5/ProductDetail?id=@Request["ID"]" class="ord-pro-link"><span id="productname"></span></a></h1> <p class="weui-media-box__desc">規格:<span>套</span></p> <div class="clear mg-t-10"> <div class="wy-pro-pri fl">¥<em class="num font-15" id="price">0</em></div> <div class="pro-amount fr"><div id="spinner-amount" class="Spinner"></div></div> </div> </div> </div> </div> </div>
JS處理代碼如下所示
//綁定產品明細 function GetProductDetail() { var url = "/H5/GetProductDetail"; var data = { id: "@Request["ID"]" } //獲取數據並綁定界面 $.getJSON(url, data, function (result) { $("#productname").text(result.ProductName); $("#price").text(result.Price); $("#productimg").attr("src", result.Picture); //$("#description").text(result.Description); $("#totalmoney").text(result.Price); }); }
而微信支付的處理,我們可以通過參考官方的介面定義來處理我們的代碼。
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6
我們先來金額彙總的界面展示,通過按鈕我們發起微信支付的處理操作。
<!--金額及發起支付--> <div class="wy-media-box weui-media-box_text"> <div class="mg10-0 t-c">總金額:<span class="wy-pro-pri mg-tb-5">¥<em class="num font-20" id="totalmoney">0</em></span></div> <div class="mg10-0"><a onclick="PayMoney()" class="weui-btn weui-btn_primary">微信付款</a></div> <div class="mg10-0"><a href="/h5/ProductList" class="weui-btn weui-btn_plain-primary">返回產品列表</a></div> </div>
參考下官方案例,我們處理的JS代碼如下所示。
//微信支付的調用處理 function onBridgeReady() { //統一下單的數據 var total_fee = parseFloat($("#totalmoney").text()) * 100;//轉換為分單位 var data = { total_fee: total_fee, //訂單金額,單位為分 body: $("#productname").text(), //商品或支付單簡要描述 detail: $("#productname").text(), //商品名稱明細列表 openid: "@ViewBag.openid", //當前用戶標識 product_id: "@Request["ID"]", //商品ID, trade_type=NATIVE,此參數必傳 trade_type: "JSAPI", //交易類型, JSAPI--公眾號支付、NATIVE--原生掃碼支付、APP--app支付 attach: "附加數據", // 附加數據,在查詢API和支付通知中原樣返回,該欄位主要用於商戶攜帶訂單的自定義數據 }; //獲取預下單參數並調用支付處理 var url = "/h5/GetPreOrder"; $.getJSON(url, data, function (info) { WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId": info.appId, //公眾號名稱,由商戶傳入 "timeStamp": info.timeStamp, //時間戳,自1970年以來的秒數 "nonceStr": info.nonceStr, //隨機串 "package": info.package, "signType": info.signType, //微信簽名方式: "paySign": info.paySign //微信簽名 }, function (res) { switch (res.err_msg) { case 'get_brand_wcpay_request:cancel': $.alert("取消支付"); break; case 'get_brand_wcpay_request:fail': $.alert("支付失敗,可能的原因:簽名錯誤、未註冊APPID、項目設置APPID不正確、註冊的APPID與設置的不匹配、其他異常等。"); break; case 'get_brand_wcpay_request:ok': $.alert("支付成功"); break; } }); }); } //微信付款 function PayMoney() { 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(); } }
這裡的支付所需的參數,我們通過後端的/h5/GetPreOrder 獲取生成,然後通過JS進行非同步發起支付操作。
這個GetPreOrder主要的操作就是根據我們傳入的商品信息,然後獲取對應的參數返回給前端。
/// <summary> /// 預生成訂單支付需要的前端參數 /// </summary> /// <param name="order">訂單數據</param> /// <returns></returns> public ActionResult GetPreOrder(PayOrderData order) { dynamic obj = new ExpandoObject(); if (order != null && order.total_fee > 0) { //調用支付API,獲取統一下單數據 var payApi = new TenPayApi(this.accountInfo); var preResult = payApi.UnifiedOrder(order); var prepay_id = preResult.prepay_id;//預支付回話標識 //生成支付所需數據和簽名 WxPayData data = new WxPayData(); data.SetValue("appId", accountInfo.AppID);//公眾帳號id data.SetValue("timeStamp", data.GenerateTimeStamp());//隨機字元串 data.SetValue("nonceStr", data.GenerateNonceStr());//隨機字元串 data.SetValue("package", string.Format("prepay_id={0}", prepay_id));//統一下單介面返回的prepay_id參數值,提交格式如:prepay_id=*** data.SetValue("signType", "MD5");//簽名類型,預設為MD5,支持HMAC-SHA256和MD5。註意此處需與統一下單的簽名類型一致 data.SetValue("paySign", data.MakeSign(accountInfo.PayAPIKey));//簽名 //構建一個前端使用的對象,用於配置支付處理的JS參數 obj.appId = accountInfo.AppID; obj.nonceStr = data.GetValue("nonceStr"); obj.timeStamp = data.GetValue("timeStamp"); obj.package = data.GetValue("package"); obj.signType = data.GetValue("signType"); obj.paySign = data.GetValue("paySign"); } return ToJsonContent(obj); }
這樣我們就可以發起微信支付處理操作了。
當然,我們JS方面,除了剛纔利用getBrandWCPayRequest 來發起支付處理,我們還可以利用微信JSSDK的chooseWXPay函數支付發起處理的,如下代碼所示。
//發起一個微信支付 function chooseWXPay() { //統一下單的數據 var total_fee = parseFloat($("#totalmoney").text()) * 100;//轉換為分單位 var data = { total_fee: total_fee, //訂單金額,單位為分 body: $("#productname").text(), //商品或支付單簡要描述 detail: $("#productname").text(), //商品名稱明細列表 openid: "@ViewBag.openid", //當前用戶標識 product_id: "@Request["ID"]", //商品ID, trade_type=NATIVE,此參數必傳 trade_type: "JSAPI", //交易類型, JSAPI--公眾號支付、NATIVE--原生掃碼支付、APP--app支付 attach: "附加數據", // 附加數據,在查詢API和支付通知中原樣返回,該欄位主要用於商戶攜帶訂單的自定義數據 }; //獲取預下單參數並調用支付處理 var url = "/h5/GetPreOrder"; $.getJSON(url, data, function (info) { wx.chooseWXPay({ appId: info.appId, timestamp: info.timeStamp, // 支付簽名時間戳,註意微信jssdk中的所有使用timestamp欄位均為小寫。但最新版的支付後臺生成簽名使用的timeStamp欄位名需大寫其中的S字元 nonceStr: info.nonceStr, // 支付簽名隨機串,不長於 32 位 package: info.package, // 統一支付介面返回的prepay_id參數值,提交格式如:prepay_id=***) signType: info.signType, // 簽名方式,預設為'SHA1',使用新版支付需傳入'MD5' paySign: info.paySign, // 支付簽名 success: function (res) { // 支付成功後的回調函數 if (res.errMsg == 'chooseWXPay:ok') { $.toast('支付成功'); //setTimeout(function () { // window.location.href = "/";//這裡預設跳轉到主頁 //}, 2000); //window.location.href = "/Pay/order_details?orderId=" + $("#orderId").val(); } else if (res.errMsg == 'chooseWXPay:cancel' || res.errMsg == 'chooseWXPay:fail') { $.toast("支付失敗"); //window.location.href = "/Pay/order_details?orderId=" + $("#orderId").val(); } }, cancel: function () { $.toast("用戶取消了支付2"); //window.location.href = "/Pay/order_details?orderId=" + $("#orderId").val(); } }); wx.error(function (res) { $.toast("調用支付出現異常"); }); }); }
同樣可以實現一樣的微信支付效果。
2、商品的購物車處理
前面介紹過,購物車可以從本地的localStorage對象進行獲取和處理,也可通過介面獲取資料庫記錄的購物車信息,本案例介紹通過localStorage進行購物車處理方式。
為了封裝對localStorage購物車的處理,我們引入一個對這個購物車的操作處理,主要就是添加、更新、獲取列表、清空列表等相關操作。
對於以上JS的代碼使用demo代碼如下所示。
<script> $(function () { var product = { 'id': 1, 屬性名用引號括起來,屬性間由逗號隔開 'name': '商品1', 'num': 1, 'price': 1 }; cart.addProduct(product); 商品加入到購物車 var productlist = cart.getProductList(); 取出購物車商品 console.log(productlist); var isExist = cart.existProduct(); console.log(isExist); cart.deleteProduct(1); var isExist1 = cart.existProduct(); console.log(isExist1); }); </script>
購物車列表界面如下所示,主要就是展開存儲裡面的商品信息,並彙總展示,如下所示。
這個頁面視圖的代碼如下所示。
<!--主體--> <header class="wy-header"> <div class="wy-header-icon-back"><span></span></div> <div class="wy-header-title">購物車</div> </header> <div class="weui-content" id="divCart"> </div> <!--底部導航--> <div class="foot-black"></div> <div class="weui-tabbar wy-foot-menu"> <div class="npd cart-foot-check-item weui-cells_checkbox allselect"> <div class="weui-cell allsec-well weui-check__label" for="all"> <div class="weui-cell__hd"> <input type="checkbox" class="weui-check" name="all-sec" id="all"> <i class="weui-icon-checked"></i> </div> <div class="weui-cell__bd"> <p class="font-14">全選</p> </div> </div> </div> <div class="weui-tabbar__item npd"> <p class="cart-total-txt">合計:<i>¥</i><em class="num font-16" id="zong1">0.00</em></p> </div> <a href="/h5/shopcartorder" class="red-color npd w-90 t-c"> <p class="promotion-foot-menu-label">去結算</p> </a> </div>
這裡主要就是根據數據,動態構建divCart裡面的列表數據,相關的JS代碼如下所示。
//顯示購物車列表 function showCartList() { var productlist = cart.getProductList(); //取出購物車商品 $("#divCart").html(""); //構建HTML控制項 $.each(productlist, function (i, item) { var html = ` <div class="weui-panel weui-panel_access"> <div class="weui-panel__hd"><span>廣州愛奇迪</span><a href="javascript:;" class="wy-dele"></a></div> <div class="weui-panel__bd"> <div class="weui-media-box_appmsg pd-10"> <div class="weui-media-box__hd check-w weui-cells_checkbox"> <div class="weui-check__label" for="cart-pto1"> <div class="weui-cell__hd cat-check"><input type="checkbox" class="weui-check" name="cartpro" id="cart-pto1"><i class="weui-icon-checked"></i></div> </div> </div> <div class="weui-media-box__hd"><a href="/h5/ProductDetail?id=${item.id}"><img class="weui-media-box__thumb" src="${item.picture}" alt=""></a></div> <div class="weui-media-box__bd"> <h1 class="weui-media-box__desc"><a href="/h5/ProductDetail?id=${item.id}" class="ord-pro-link">${item.name}</a></h1> <p class="weui-media-box__desc">規格:<span>套</span></p> <div class="clear mg-t-10"> <div class="wy-pro-pri fl">¥<em class="num font-15">${item.price}</em></div> <div class="pro-amount fr"> <div class="weui-count"> <a class="weui-count__btn weui-count__decrease"></a> <input class="weui-count__number" type="number" value="${item.num}" /> <a class="weui-count__btn weui-count__increase"></a> <input type="hidden" class="pro-