簡介
這裡介紹了一次在微信WebView中使用Vue做單頁應用的過程中遇到的一些問題,也是比較常見的問題。文末有亮點,希望大家都來~
背景
最近因為快過年了,按照微信以往的尿性,小程式的稽核總是有各種條條框框,因此為了讓活動線上上正常進行且進行版本的迭代,(主要是為了能得到多一些的開發時間)我們打算採用h5來做活動。
目錄
-
微信小程式跳轉WebView的問題;
-
wx.config
進行初始化比較優雅的書寫方式; -
微信簽名的一些問題;
-
Vue單頁應用在微信瀏覽器內遇到的一些問題(包含微信支付);
-
單頁應用內的通訊;
微信小程式跳轉WebView的問題
首先,我們先來聊一聊微信跳轉到WebView的一些事情,在此之前大家可以先來看看官方給的文件:web-view · 小程式
普通的跳轉沒什麼好說的,先說說我遇到的問題:
在小程式內進入WebView,我需要把小程式中storage模擬的cookie給帶過去,調研了很多資料只得到一個方案,想要從小程式向WebView進行通訊的話只能通過拼接URL,那很絕望啊,那個cookie有多長你知道嗎??
解決方案:
其實也比較簡單,我們在小程式進入WebView之前會對cookie進行一次操作,將cookie進行md5得到一個較短的字串,通過這個md5進行拼接得到較短的URL會減少很多的問題。
注意點:
-
我們寫在URL裡邊的地址需要encodeURIComponent一下,避免在連結中帶有中文字元,否則在 iOS 中開啟頁面會有白屏的問題。
-
WebView中的openid和小程式中的openid是不一樣的,因此各位如果需要做使用者關聯的話最好用unionid。
-
跳轉的WebView地址需要在mp後臺裡邊進行加白名單,不然無法訪問,域名要求是https的。
-
我們可以通過微信開發者工具裡邊公眾平臺進行開發,你可以在裡邊除錯WebView的頁面,jssdk的報錯也可以在除錯工具中體現,最後沒有問題再通過代理的方式到手機上過一遍,這裡我用的是Charles進行代理的。
wx.config比較優雅的書寫方式
專案在引用JS-SDK的API的時候,必須先注入配置資訊,也就是wx.config
,同一個頁面(同一個URL)只需要初始化一次就OK了。wx.config
程式碼如下:
wx.config({
debug: false, // 開啟除錯模式,呼叫的所有api的返回值會在客戶端alert出來,若要檢視傳入的引數,可以在pc端開啟,引數資訊會通過log打出,僅在pc端時才會列印。
appId: '', // 必填,公眾號的唯一標識
timestamp: , // 必填,生成簽名的時間戳
nonceStr: '', // 必填,生成簽名的隨機串
signature: '',// 必填,簽名
jsApiList: [] // 必填,需要使用的JS介面列表
});
複製程式碼
具體的資訊大家可以看一下文件,這裡有一點需要特別提醒大家,寫程式碼的時候,一定要嚴格按照微信文件裡要求去寫,大小寫,資料型別都要與文件保持一致。微信公眾平臺
這些都是‘苦口婆心’的話,你要不信,可以試試╮(╯_╰)╭
我在寫程式碼的時候喜歡把不同的功能寫在不同的方法裡邊,初始化的函式只做初始化的事情,這樣感覺比較舒服。-
在所有微信介面呼叫前必須保證引入JS-SDK檔案,設定JS介面安全域名。
-
JS-SDK裡有使用者觸發時才呼叫的API,有一點需要注意一下,
wx.config
是一個客戶端的非同步操作,在使用方法的時候會存在因非同步導致的時機問題,所以方法最好寫在wx.ready
中,wx.config
資訊驗證成功後會執行wx.ready
方法。 -
我們最好在初始化的時候習慣性的寫上
wx.error
與wx.ready
同級,這樣之後方法出現問題除錯起來也會方便不少,也可以做報錯提示。
上邊的幾個點沒問題以後,我來說一下比較優雅的初始化方法,大概邏輯如下:
首先我們需要在方法外邊封裝一個Promise的模板,但是我的專案中也用了Jquery,我就直接用了裡邊的$.Deferred()
方法
let defer = $.Deferred();
let ready = defer.promise();
複製程式碼
$.Deferred()
其實就是用來返回一個鏈式實用物件方法來註冊多個回撥,裡邊有多個方法
寫好這兩個方法以後基本上就完成一半了,激不激動!
按照上邊介紹的邏輯,ready
是初始化成功,那麼回撥就是resolve
。error
是初始化失敗,回撥就是reject
。然後我們用defer.promise()
去接收兩個狀態並返回promise物件,之後你就可以愉快的then()
了。
注意:deferred.promise()
也可以接受一個 target 引數,此時傳入的 target 將被賦予 Promise 的方法,並作為結果返回,而不是建立一個新物件。
// Existing object
var obj = {
hello: function( name ) {
alert( "Hello " + name );
}
},
// Create a Deferred
defer = $.Deferred();
// Set object as a promise
defer.promise( obj );
// Resolve the deferred
defer.resolve( "John" );
// Use the object as a Promise
obj.done(function( name ) {
obj.hello( name ); // Will alert "Hello John"
}).hello( "Karl" ); // Will alert "Hello Karl"
複製程式碼
具體的你可以看看官網的介紹
這一切都準備完了,接下來我們開始初始化配置
getWxSign(){
wx.config({
debug: false,
appId: ,
timestamp: ,
nonceStr: ,
signature: ,
jsApiList: [],
});
wx.error((err) => {
defer.reject(err);
});
wx.ready(() => {
defer.resolve();
});
}
複製程式碼
這兩步都完成以後,我們的鏈式解構就完成了,可以放飛自我的書寫。
比如我想要獲取微信的收貨地址,就可以這麼寫ready.then(()=>{
wx.openAddress({
success: function (res) {},
fail: function(err) {},
cancel: function() {}
});
});
複製程式碼
通過這麼一封裝,你的程式碼的可讀性就會有一個很大提升,至少看著很舒服(自我感覺)。
當然在使用這些jssdk的API的時候大家要記得加一個?,不然會有多次呼叫的情況,可能會出現返回好幾次的情況,當然這個我沒有試過,大家可以zuo一下。
微信簽名的一些問題
關於微信簽名失效的問題,這裡主要是想提一下,因為這一塊服務端的程式碼是另外一個小夥伴寫的,所以我並沒有太多的實踐,微信簽名服務端最好快取一下access_token。這樣可以避免很多不必要的麻煩。
官方是這麼說的:公眾平臺以access_token為介面呼叫憑據,來呼叫介面,所有介面的呼叫需要先獲取access_token,access_token在2小時內有效(7200s),過期需要重新獲取,但1天內獲取次數有限,開發者需自行儲存。
其實在開發之初,服務端的同學還沒寫完這一塊邏輯的時候,前端的同學可以這麼去除錯,先讓服務端獲取一次配置資訊,然後前端暫時先把這一塊寫死,這樣最少兩個小時之內是沒問題的,可以提高開發的效率。
還有一點,在快取的有效期內提前去重新整理新access_token,這個讓服務端的同學統一控制,不要各自重新整理,這樣會出現衝突的情況,錯誤體現為invalid signature。確認這類錯的時候我們需要充分利用官方給的簽名校驗工具
如果是因為token過期導致的簽名失敗,基本上在輸入token以後就直接提示了,這個時候就要看看是不是服務端的快取時間出了問題,當時我們遇到問題的原因是服務端底層關於時間的計算多*60...
當然出現簽名錯誤還有許多的問題,在確保簽名演算法沒有問題的情況下,可能會如下幾種情況:
-
年少不知微信虎,引數大小寫沒有按照官方要求書寫。重點需要注意一下nonceStr,timestamp兩個欄位。timestamp的資料型別是String,這個也要注意下。
-
確認URL是頁面完整的url。可以通過
location.href.split('#')[0]
確認,目錄的話只要填寫都按上一級即可。
假如地址為:
https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
那麼你的URL可以寫到上一級
https://mp.weixin.qq.com/debug/cgi-bin
複製程式碼
-
config 與獲取ticket的AppID不一致。
-
還有就是服務端如果沒有快取access_token,我們在除錯的時候多刷幾下可能就會出現問題了,因為開發的時候我感覺刷個幾百上千還是很有可能的。
-
前端傳遞的URL可能會encodeURIComponent處理過的,服務端需要decode。
-
還有一個服務端獲取的URL與前端的URL不一致,這個在手機上開啟以後你可以複製一下連結檢查一下。
vue單頁應用在微信瀏覽器內遇到的一些問題
因為這回我們活動用的是vue的單頁應用去完成的,路由用vue-router的history模式,因此會遇到一個比較煩躁的問題,具體的問題我描述一下場景:
在iOS上商品詳情頁跳轉到訂單詳情頁面進行支付,支付頁面需要調起兩個方法,而我的wx.config是mounted的時候就初始化的,所以每次進入這個頁面都會報一個invalid signature,我就納悶了,無意間發現重新整理了一下頁面就正常了。有時候不報這個簽名問題地址也能使用,但是每次支付的時候他就報地址不對。最後我上網查了半天我就發現,history模式下,簽名使用的URL是剛進入頁面時的URL,為了確認是不是這個問題我把每一頁的URL都貼出來,還真是都一樣,既然問題確認了,那就好解決了。
解決思路:
在進入頁面的時候我們可以先檢測一下手機的型別,前邊也說了我是在iOS的系統上遇到的問題,在安卓上就沒問題,所以無需要對iOS專門處理一下,只要是識別到iOS的機型,那麼我就把地址給改了,程式碼可以參考如下:
// 專門相容iOS上微信簽名的問題
beforeRouteEnter(to, from, next) {
var isiOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios終端
if (isiOS && to.path !== location.pathname) {
location.assign(to.fullPath)
} else {
next();
}
},
複製程式碼
當然,解決的辦法不止這一個,其實有很多的解決方案,就是感覺其實不太優雅,當時其實我的備用方案就是要麼用a標籤進行頁面跳轉,或者進入這個頁面以後,你可以reload
一下來更新URL。選擇怎樣的方法大家自己選擇吧。
單頁應用內的通訊
首先我說一下場景大家方便理解一下目的。當時在做專案的時候整個專案只有一塊功能用到這通訊,當時服務端的童鞋讓我不要在表單頁面進行提交,因為內容不多,讓我把資訊帶到訂單頁面結算時一起提交,這個其實就是非父子元件之間的通訊,但是這個需要通訊的地方沒那麼多,引入一個vuex感覺太重了,我就直接不考慮這個方案了,就然這個不用,那就直接用eventBus其實也可以,程式碼如下:
首先我們需要宣告一個eventBus的js檔案:
import Vue from 'vue';
var eventBus = new Vue({});
export default eventBus;
複製程式碼
接下來你需要傳遞你的值:
import eventBus from 'eventBus/eventBus.js';
let info = {
a: '',
b: ''
};
eventBus.$emit('isVal',info);
複製程式碼
我們在提交表單的頁面加一個emit
的事件,把填寫的內容傳出去,接下來我們就要跳回到訂單頁面了。
import eventBus from 'eventBus/eventBus.js';
eventBus.$on('isVal',(data)=>{
//....
});
複製程式碼
使用on
進行接收,這樣就完成了,其實也是比較簡單的邏輯,沒涉及到太多東西,對了這個監聽可以放在mounted
或者create
裡邊,建議用once
就OK了。
我們開發的小程式叫做一番市集,歡迎大家註冊體驗,可以加微信zyf348519452聯絡我要邀請碼哦。