對需求進行抽象,其實要的就是一個過濾器,對小程序頁面的訪問進行過濾,符合條件的經過,不符合條件進行其餘處理。php
使用過php的laravel框架的童鞋,確定一會兒就聯想到了laravel框架的http中間件:HTTP 中間件提供一個方便的機制來過濾進入應用程序的 HTTP 請求,例如,Laravel 默認包含了一箇中間件來檢驗用戶身份驗證,若是用戶沒有通過身份驗證,中間件會將用戶導向登陸頁面,然而,若是用戶經過身份驗證,中間件將會容許這個請求進一步繼續前進。固然,除了身份驗證以外,中間件也能夠被用來執行各式各樣的任務,CORS 中間件負責替全部即將離開程序的響應加入適當的響應頭,一個日誌中間件能夠記錄全部傳入應用程序的請求。
laravel
使人憂桑的是,微信小程序並無提供針對Page實例的中間件機制。因此只能從Page實例的生命週期處下手。小程序
對於onLoad,一個頁面只會調用一次;對於onShow,每次打開頁面(好比小程序從後臺轉到前臺)都會調用一次。微信小程序
在onLoad或者onShow鉤子函數裏,對用戶身份進行校驗,經過後則拉取該頁面須要的數據,不然跳轉到登陸頁。promise
//orderDetail.js onShow: function () { let that = this; //身份校驗 service.identityCheck(() => { //跳轉到登陸頁 wx.redirectTo({ url: "/pages/common/login/login" }); }, () => { //獲取頁面數據等等 that.getDetail(this.orderId); ... } ); },
不過,每一個頁面都要這樣寫,重複代碼好多啊,侵入性也強。不如用裝飾函數(高大上的說法是裝飾者模式)來包裝一下:微信
//filter.js function identityFilter(pageObj){ if(pageObj.onShow){ let _onShow = pageObj.onShow; pageObj.onShow = function(){ service.identityCheck(()=>{ //跳轉到登陸頁 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
用以提供過濾器方法,除了現有的用戶身份攔截,後續若是須要其餘攔截,能夠在這個文件增長。而後,在須要用戶身份攔截的小程序頁面代碼裏,用filter.identityFilter
處理一下就能夠了:app
//orderDetail.js let filter = require('filter.js'); Page(filter.identityFilter({ ... onShow: function () { //獲取頁面數據等等 this.getDetail(this.orderId); //... }, ... }));
上面的實現中,每次訪問頁面,都會執行一次獲取用戶身份的方法(就是上面代碼裏的service. identityCheck
)。其實沒有必要,在小程序啓動的時候獲取一次就好了。也就是說,放在app.js的onLaunch方法裏執行。框架
每一個小程序頁面實例化時,通常也會執行異步方法,用來獲取頁面須要的數據。關鍵在於,咱們須要保證,頁面的異步方法 必須在 獲取用戶身份的異步請求 以後執行。異步
毋容置疑,Promise最擅長處理異步請求的執行順序了。主子,快放代碼粗來:ide
//app.js App({ onLaunch:function(){ let p = new Promise(function(resolve,reject){ service.identityCheck(resolve,reject); }); this.globalData.promise = p; }, ... globalData: { promise:null, } });
//filter.js const appData = getApp().globalData; function identityFilter(pageObj){ if(pageObj.onShow){ let _onShow = pageObj.onShow; pageObj.onShow = function(){ //改動點 appData.promise.then(()=>{ //跳轉到登陸頁 wx.redirectTo({ url: "/pages/common/login/login" }); },()=>{ //獲取頁面實例,防止this劫持 let currentInstance = getPageInstance(); _onShow.call(currentInstance); }); } } return pageObj; }
基本實現了小程序頁面的用戶身份攔截器,可是比起laravel的http中間件仍是遜色一些:
嗯,對小程序的新特性保持關注,後面看看怎麼改進~