這裏介紹了一次在微信WebView中使用Vue作單頁應用的過程當中遇到的一些問題,也是比較常見的問題。文末有亮點,但願你們都來~html
最近由於快過年了,按照微信以往的尿性,小程序的審覈老是有各類條條框框,所以爲了讓活動在線上正常進行且進行版本的迭代,(主要是爲了能獲得多一些的開發時間)咱們打算採用h5來作活動。前端
微信小程序跳轉WebView的問題;vue
wx.config
進行初始化比較優雅的書寫方式;jquery
微信簽名的一些問題;ios
Vue單頁應用在微信瀏覽器內遇到的一些問題(包含微信支付);web
單頁應用內的通訊;算法
首先,咱們先來聊一聊微信跳轉到WebView的一些事情,在此以前你們能夠先來看看官方給的文檔:web-view · 小程序vue-router
普通的跳轉沒什麼好說的,先說說我遇到的問題:vuex
在小程序內進入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進行代理的。
項目在引用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-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聯繫我要邀請碼哦。