場(chǎng)景
需求分析&實(shí)現(xiàn)
對(duì)需求進(jìn)行抽象,其實(shí)要的就是一個(gè)過(guò)濾器,對(duì)小程序頁(yè)面的訪問(wèn)進(jìn)行過(guò)濾,符合條件的通過(guò),不符合條件進(jìn)行其他處理。
使用過(guò)php的laravel框架的童鞋,肯定一下子就聯(lián)想到了laravel框架的http中間件:
HTTP 中間件提供一個(gè)方便的機(jī)制來(lái)過(guò)濾進(jìn)入應(yīng)用程序的 HTTP 請(qǐng)求,例如,Laravel 默認(rèn)包含了一個(gè)中間件來(lái)檢驗(yàn)用戶身份驗(yàn)證,如果用戶沒(méi)有經(jīng)過(guò)身份驗(yàn)證,中間件會(huì)將用戶導(dǎo)向登錄頁(yè)面,然而,如果用戶通過(guò)身份驗(yàn)證,中間件將會(huì)允許這個(gè)請(qǐng)求進(jìn)一步繼續(xù)前進(jìn)。當(dāng)然,除了身份驗(yàn)證之外,中間件也可以被用來(lái)執(zhí)行各式各樣的任務(wù),CORS 中間件負(fù)責(zé)替所有即將離開程序的響應(yīng)加入適當(dāng)?shù)捻憫?yīng)頭,一個(gè)日志中間件可以記錄所有傳入應(yīng)用程序的請(qǐng)求。
令人憂桑的是,微信小程序并沒(méi)有提供針對(duì)Page實(shí)例的中間件機(jī)制。所以只能從Page實(shí)例的生命周期處下手。
對(duì)于onLoad,一個(gè)頁(yè)面只會(huì)調(diào)用一次;對(duì)于onShow,每次打開頁(yè)面(比如小程序從后臺(tái)轉(zhuǎn)到前臺(tái))都會(huì)調(diào)用一次。
在onLoad或者onShow鉤子函數(shù)里,對(duì)用戶身份進(jìn)行校驗(yàn),通過(guò)后則拉取該頁(yè)面需要的數(shù)據(jù),否則跳轉(zhuǎn)到登錄頁(yè)。
//orderDetail.js onShow: function () { let that = this; //身份校驗(yàn) service.identityCheck(() => { //跳轉(zhuǎn)到登錄頁(yè) wx.redirectTo({ url: "/pages/common/login/login" }); }, () => { //獲取頁(yè)面數(shù)據(jù)等等 that.getDetail(this.orderId); ... } ); },
不過(guò),每個(gè)頁(yè)面都要這樣寫,重復(fù)代碼好多啊,侵入性也強(qiáng)。不如用裝飾函數(shù)(高大上的說(shuō)法是裝飾者模式)來(lái)包裝一下:
//filter.js function identityFilter(pageObj){ if(pageObj.onShow){ let _onShow = pageObj.onShow; pageObj.onShow = function(){ service.identityCheck(()=>{ //跳轉(zhuǎn)到登錄頁(yè) wx.redirectTo({ url: "/pages/common/login/login" }); },()=>{ //獲取頁(yè)面實(shí)例,防止this劫持 let currentInstance = getPageInstance(); _onShow.call(currentInstance); }); } } return pageObj; } function getPageInstance(){ var pages = getCurrentPages(); return pages[pages.length - 1]; } exports.identityFilter = identityFilter;
filter.js
用以提供過(guò)濾器方法,除了現(xiàn)有的用戶身份攔截,后續(xù)如果需要其他攔截,可以在這個(gè)文件增加。然后,在需要用戶身份攔截的小程序頁(yè)面代碼里,用filter.identityFilter
處理一下就可以了:
//orderDetail.js let filter = require('filter.js'); Page(filter.identityFilter({ ... onShow: function () { //獲取頁(yè)面數(shù)據(jù)等等 this.getDetail(this.orderId); //... }, ... }));
使用Promise進(jìn)行優(yōu)化
上面的實(shí)現(xiàn)中,每次訪問(wèn)頁(yè)面,都會(huì)執(zhí)行一次獲取用戶身份的方法(就是上面代碼里的service. identityCheck )。其實(shí)沒(méi)有必要,在小程序啟動(dòng)的時(shí)候獲取一次就行了。也就是說(shuō),放在app.js的onLaunch方法里執(zhí)行。
每個(gè)小程序頁(yè)面實(shí)例化時(shí),一般也會(huì)執(zhí)行異步方法,用來(lái)獲取頁(yè)面需要的數(shù)據(jù)。關(guān)鍵在于,我們需要保證,頁(yè)面的異步方法 必須在 獲取用戶身份的異步請(qǐng)求 之后執(zhí)行。
毋容置疑,Promise最擅長(zhǎng)處理異步請(qǐng)求的執(zhí)行順序了。主子,快放代碼粗來(lái):
//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(){ //改動(dòng)點(diǎn) appData.promise.then(()=>{ //跳轉(zhuǎn)到登錄頁(yè) wx.redirectTo({ url: "/pages/common/login/login" }); },()=>{ //獲取頁(yè)面實(shí)例,防止this劫持 let currentInstance = getPageInstance(); _onShow.call(currentInstance); }); } } return pageObj; }
小結(jié)
基本實(shí)現(xiàn)了小程序頁(yè)面的用戶身份攔截器,但是比起laravel的http中間件還是遜色一些:
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com