微信單頁應用的那些事

Yuanf發表於2019-03-12

簡介

這裡介紹了一次在微信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.errorwx.ready同級,這樣之後方法出現問題除錯起來也會方便不少,也可以做報錯提示。

上邊的幾個點沒問題以後,我來說一下比較優雅的初始化方法,大概邏輯如下:

首先我們需要在方法外邊封裝一個Promise的模板,但是我的專案中也用了Jquery,我就直接用了裡邊的$.Deferred()方法

let defer = $.Deferred();
let ready = defer.promise();
複製程式碼

$.Deferred()其實就是用來返回一個鏈式實用物件方法來註冊多個回撥,裡邊有多個方法

寫好這兩個方法以後基本上就完成一半了,激不激動!

微信單頁應用的那些事
按照上邊介紹的邏輯,ready是初始化成功,那麼回撥就是resolveerror是初始化失敗,回撥就是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"
複製程式碼

具體的你可以看看官網的介紹

jQuery API Documentation

這一切都準備完了,接下來我們開始初始化配置


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。確認這類錯的時候我們需要充分利用官方給的簽名校驗工具

微信 JS 介面簽名校驗工具

如果是因為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聯絡我要邀請碼哦。

微信單頁應用的那些事

相關文章