小程序有52個頁面,其中13個頁面無需任何身份,另外39個頁面需要系統(tǒng)角色。對于這39個頁面,如果微信用戶沒有系統(tǒng)角色,則跳轉(zhuǎn)到登錄頁。是否有系統(tǒng)角色信息需要通過異步請求來獲取。 ...
對需求進(jìn)行抽象,其實要的就是一個過濾器,對小程序頁面的訪問進(jìn)行過濾,符合條件的通過,不符合條件進(jìn)行其他處理。
使用過php的laravel框架的童鞋,肯定一下子就聯(lián)想到了laravel框架的http中間件:
HTTP 中間件提供一個方便的機制來過濾進(jìn)入應(yīng)用程序的 HTTP 請求,例如,Laravel 默認(rèn)包含了一個中間件來檢驗用戶身份驗證,如果用戶沒有經(jīng)過身份驗證,中間件會將用戶導(dǎo)向登錄頁面,然而,如果用戶通過身份驗證,中間件將會允許這個請求進(jìn)一步繼續(xù)前進(jìn)。當(dāng)然,除了身份驗證之外,中間件也可以被用來執(zhí)行各式各樣的任務(wù),CORS 中間件負(fù)責(zé)替所有即將離開程序的響應(yīng)加入適當(dāng)?shù)捻憫?yīng)頭,一個日志中間件可以記錄所有傳入應(yīng)用程序的請求。
令人憂桑的是,微信小程序并沒有提供針對Page實例的中間件機制。所以只能從Page實例的生命周期處下手。

對于onLoad,一個頁面只會調(diào)用一次;對于onShow,每次打開頁面(比如小程序從后臺轉(zhuǎn)到前臺)都會調(diào)用一次。
onLoad或者onShow鉤子函數(shù)里,對用戶身份進(jìn)行校驗,通過后則拉取該頁面需要的數(shù)據(jù),否則跳轉(zhuǎn)到登錄頁。
//orderDetail.jsonShow: function () {let that = this;//身份校驗service.identityCheck(() => {//跳轉(zhuǎn)到登錄頁wx.redirectTo({url: "/pages/common/login/login"});}, () => { //獲取頁面數(shù)據(jù)等等 that.getDetail(this.orderId);...});},不過,每個頁面都要這樣寫,重復(fù)代碼好多啊,侵入性也強。不如用裝飾函數(shù)(高大上的說法是裝飾者模式)來包裝一下:
//filter.jsfunction identityFilter(pageObj){if(pageObj.onShow){let _onShow = pageObj.onShow;pageObj.onShow = function(){service.identityCheck(()=>{//跳轉(zhuǎn)到登錄頁wx.redirectTo({url: "/pages/common/login/login"});},()=>{//獲取頁面實例,防止this劫持let currentInstance = getPageInstance();_onShow.call(currentInstance);});}}return pageObj;}function getPageInstance(){var pages = getCurrentPages();return pages[pages.length - 1];}exports.identityFilter = identityFilter;filter.js用以提供過濾器方法,除了現(xiàn)有的用戶身份攔截,后續(xù)如果需要其他攔截,可以在這個文件增加。然后,在需要用戶身份攔截的小程序頁面代碼里,用filter.identityFilter處理一下就可以了:
//orderDetail.jslet filter = require('filter.js');Page(filter.identityFilter({...onShow: function () {//獲取頁面數(shù)據(jù)等等this.getDetail(this.orderId);//...},...}));使用Promise進(jìn)行優(yōu)化
上面的實現(xiàn)中,每次訪問頁面,都會執(zhí)行一次獲取用戶身份的方法(就是上面代碼里的service. identityCheck)。其實沒有必要,在小程序啟動的時候獲取一次就行了。也就是說,放在app.js的onLaunch方法里執(zhí)行。
每個小程序頁面實例化時,一般也會執(zhí)行異步方法,用來獲取頁面需要的數(shù)據(jù)。關(guān)鍵在于,我們需要保證,頁面的異步方法 必須在 獲取用戶身份的異步請求 之后執(zhí)行。
毋容置疑,Promise最擅長處理異步請求的執(zhí)行順序了。主子,快放代碼粗來:
//app.jsApp({onLaunch:function(){let p = new Promise(function(resolve,reject){service.identityCheck(resolve,reject);});this.globalData.promise = p; },...globalData: {promise:null,} });//filter.jsconst appData = getApp().globalData;function identityFilter(pageObj){if(pageObj.onShow){let _onShow = pageObj.onShow;pageObj.onShow = function(){//改動點appData.promise.then(()=>{//跳轉(zhuǎn)到登錄頁wx.redirectTo({url: "/pages/common/login/login"});},()=>{//獲取頁面實例,防止this劫持let currentInstance = getPageInstance();_onShow.call(currentInstance);});}}return pageObj;}基本實現(xiàn)了小程序頁面的用戶身份攔截器,但是比起laravel的http中間件還是遜色一些:
嗯,對小程序的新特性保持關(guān)注,后面看看怎么改進(jìn)~