微信小程序之頁(yè)面攔截器的示例代碼
場(chǎng)景
- 小程序有52個(gè)頁(yè)面,其中13個(gè)頁(yè)面無(wú)需任何身份,另外39個(gè)頁(yè)面需要系統(tǒng)角色。對(duì)于這39個(gè)頁(yè)面,如果微信用戶沒(méi)有系統(tǒng)角色,則跳轉(zhuǎn)到登錄頁(yè)。
- 是否有系統(tǒng)角色信息需要通過(guò)異步請(qǐng)求來(lái)獲取。
需求分析&實(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é)替所有即將離開(kāi)程序的響應(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,每次打開(kāi)頁(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中間件還是遜色一些:
- 需要對(duì)每個(gè)頁(yè)面代碼包裝一層。
- 即使用戶身份校驗(yàn)不通過(guò),小程序也并不會(huì)阻塞頁(yè)面的渲染。假如獲取用戶身份的異步方法一分鐘才執(zhí)行完,小程序頁(yè)面還是會(huì)展示出來(lái),一分鐘之后才跳轉(zhuǎn)到登錄頁(yè)。需要自己增加邏輯,比如在這一分鐘內(nèi),頁(yè)面展示空白內(nèi)容。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
根據(jù)表格中的某一列進(jìn)行排序的javascript代碼
根據(jù)表格中的某一列進(jìn)行排序的實(shí)現(xiàn)方法有很多,下面為大家介紹下如何使用js來(lái)簡(jiǎn)單實(shí)現(xiàn)下,需要的朋友不要錯(cuò)過(guò)2013-11-11
用于節(jié)點(diǎn)操作的API,顛覆原生操作HTML DOM節(jié)點(diǎn)的API
敏捷開(kāi)發(fā)是一種以人為核心、迭代、循序漸進(jìn)的開(kāi)發(fā)方法。在敏捷開(kāi)發(fā)中,軟件項(xiàng)目的構(gòu)建被切分成多個(gè)子項(xiàng)目,各個(gè)子項(xiàng)目的成果都經(jīng)過(guò)測(cè)試,具備集成和可運(yùn)行的特征。2010-12-12
PHP自動(dòng)加載autoload和命名空間的應(yīng)用小結(jié)
PHP的自動(dòng)加載就是我們加載實(shí)例化類的時(shí)候,不需要手動(dòng)去寫require來(lái)導(dǎo)入這個(gè)class.php文件,程序自動(dòng)幫我們加載導(dǎo)入進(jìn)來(lái)這.篇文章主要介紹了PHP自動(dòng)加載autoload和命名空的應(yīng)用,需要的朋友可以參考下2017-12-12
淺談tudou土豆網(wǎng)首頁(yè)圖片延遲加載的效果
經(jīng)常上tudou網(wǎng),發(fā)現(xiàn)tudou首頁(yè)加載圖片的功能很有意思,tudou首頁(yè)從"娛樂(lè)"這個(gè)板塊往下的所有視頻的縮略圖并不是在頁(yè)面打開(kāi)后就加載的,而是當(dāng)用戶拖動(dòng)滾動(dòng)條到了"娛樂(lè)"這個(gè)板塊,才開(kāi)始加載圖片的。2010-06-06
javascript延時(shí)加載之defer測(cè)試
偶爾發(fā)現(xiàn) js 中有個(gè)延時(shí)加載的標(biāo)簽 defer,還在疑惑這么好用的東西為什么沒(méi)有流行起來(lái),本人今天把它拾起來(lái)用了一下,發(fā)現(xiàn)只在ie7,8,9和360安全濟(jì)覽器下可以,知道為什么不用它了吧2012-12-12
微信小程序開(kāi)發(fā)之視頻播放器 Video 彈幕 彈幕顏色自定義實(shí)例
本篇文章主要介紹了微信小程序開(kāi)發(fā)之視頻播放器 Video 彈幕 彈幕顏色自定義實(shí)例,具有一定的參考價(jià)值,有興趣的同學(xué)可以了解一下。2016-12-12
關(guān)于二級(jí)域名下使用一級(jí)域名下的COOKIE的問(wèn)題
我們通常在使用cookie的時(shí)候一般都只是局限在本站內(nèi)使用,也就是只在一個(gè)域名下使用2011-11-11

