微信小程序中實現(xiàn)訂閱者模式(轉自csdn)可用于多頁面間動態(tài)數(shù)據(jù)共享

訂閱發(fā)布模式

在開始之前先讓大家看一段代碼

wx.getUserInfo({
   success: res => {
     // 可以將 res 發(fā)送給后臺解碼出 unionId
     this.globalData.userInfo = res.userInfo
     // 由于 getUserInfo 是網絡請求,可能會在 Page.onLoad 之后才返回
     // 所以此處加入 callback 以防止這種情況
     if (this.userInfoReadyCallback) {
       this.userInfoReadyCallback(res)
     }
   }
})
---------------------------------------------------
if (app.globalData.userInfo) {
   this.setData({
     userInfo: app.globalData.userInfo,
     hasUserInfo: true
   })
} else if (this.data.canIUse){
   // 由于 getUserInfo 是網絡請求页徐,可能會在 Page.onLoad 之后才返回
   // 所以此處加入 callback 以防止這種情況
   app.userInfoReadyCallback = res => {
     this.setData({
       userInfo: res.userInfo,
       hasUserInfo: true
     })
   }
}

想必開發(fā)過微信小程序的都認得吧苏潜。這是微信的一個回調方法,因為請求是異步的变勇,可能存在延遲恤左,當它還沒有儲存到 app.globalData 時,索引界面(第一個頁面)的 onload 已經執(zhí)行過了搀绣。此時飞袋,如果需要使用在 app.js 中的數(shù)據(jù),極大概率是空值链患,因此巧鸭,微信的做法是在索引界面的 onload 中判斷是否存在,不存在則繼續(xù)請求一次麻捻,然后將異步的值直接回調給自己纲仍。這種思路方法在我懵懂無知時簡直如同鳳姐得到那本規(guī)則世界的《故事會》一樣激動,以至于我常常覺得自己是盧瑟界的 chosen one 贸毕。

收郑叠,回到主題。今天我們將使用一種更加簡單明棍,直觀的模式去處理幾個小程序中經常遇到的麻煩事乡革。除了上面提到的,我想大家應該經常遇到的一項需求就是需要跳轉頁面的 自定義搜索 —— 在另一個頁面中輸入搜索的信息击蹲,點擊確定后署拟,wx.navigateBack() 返回上一頁面并且根據(jù)搜索內容顯示相應結果婉宰。我先來說一下我一開始的做法:

  • 將自定義搜索頁輸入的數(shù)據(jù)儲存在 app.globalData
  • 跳轉回上一頁面歌豺,在 onshow 里獲取app.globalData 中對應的數(shù)據(jù),進行后續(xù)的查詢操作
  • 查詢完成心包,清空剛才存在 app.globalData 中的數(shù)據(jù)

這樣做雖然解決了這個問題类咧,但是每次展示頁面都需要onshow無疑會增大開銷,數(shù)據(jù)重新setData也會造成屏閃。 這還僅僅是一個頁面痕惋,如果消費頁面有多個就更加麻煩区宇。

另一個例子,在用戶登錄之后值戳,根據(jù) openid 創(chuàng)建一個 mqtt(socket) 長鏈接议谷。當信息到達時由鏈接頁面分別發(fā)給各個子頁面。比如堕虹,此時卧晓,鏈接發(fā)送給我一條信息 “空調制冷24℃”,我首先需要將空調頁組件化赴捞,在 properties 中創(chuàng)建一個入口用來接收信息,其次逼裆,使用observers 對入口進行監(jiān)聽,最后在鏈接頁引入組件赦政,把信息 setData 后通過傳給空調組件胜宇。天啊,我都說暈了恢着,如果我的鏈接頁和空調頁隔了多個頁面呢桐愉,如:主頁(鏈接頁)——>房間頁——> 設備列表頁——>空調頁。不敢想然评,層層去 setData 這是多大的開銷啊仅财。

鋪墊了這么久,下面該主角登場了(要不是屏幕正上方出現(xiàn)了“您的上機時間只剩5分鐘碗淌,請及時續(xù)費”盏求,我還能扯到雞吃盡米山,狗舔完面山)亿眠。

訂閱者模式碎罚,是將所有事件調度到一起,然后將事件分發(fā)給對應的訂閱者纳像。

如圖:

在這里插入圖片描述

代碼實現(xiàn)

話不多說荆烈,都在酒里了。

class envet{
    constructor(){
        this.msg = {} //首先創(chuàng)建一個集合用來儲存所有訂閱的事件
    }

    /**
     * subscribe 用來訂閱要回調的事件
     * @param {*} key 事件的標識符
     * @param {*} fn  回調函數(shù)
     */
    subscribe(key, fn){
        if(typeof fn != 'function') return //訂閱事件不是函數(shù)直接返回
        if(!this.msg[key]) this.msg[key] = [] //不存在的事件創(chuàng)建
        this.msg[key].push(fn)   //添加函數(shù)到事件集合中竟趾。
    }

    /**
     * 發(fā)布事件方法憔购,用來通知訂閱的事件
     */
    publish(){
        //可能會疑問,為什么這里沒有key值岔帽。
        //下面這樣獲取arguments中的第一個值就是key
        let key = Array.prototype.shift.call(arguments) 
        let callBack = this.msg[key]
        if(!callBack || !callBack.length) return //集合為空就返回
        //來了玫鸟,這是重點。
        callBack.forEach(item=>{
            item.apply(this,arguments) //遍歷集合下的每個函數(shù)犀勒,依次將arguments回調給函數(shù)
            //其實屎飘,這里寫成 item.apply(null,arguments) 也行妥曲,我們需要的僅僅是arguments
        })
    }

    /**
     * 事件刪除,傳入key值(fn選填)
     * @param {*} key 
     * @param {*} fn 
     */
    remove(key,fn){
        let fns = this.msg[key]
        if(!fns || !fns.length) return //空的話返回
        if(!fn) delete this.msg[key]  //fn不填的話直接把這個集合刪了
        else{
            for(let i=0;i<fns.length;i++){
                let _item = fns[i]
                if(_item === fn || _item.fn === fn){
                    fns.splice(i,1)  //遍歷集合钦购,如果相同的話檐盟,splice
                    break
                }
            }
        }
    }
}

就是這么簡單,原理就是將 arguments 回調給訂閱的函數(shù)押桃。

嘗試效果

app.js 中創(chuàng)建:

在這里插入圖片描述

pageA 頁面訂閱:

在這里插入圖片描述

跳轉 pageB 頁面發(fā)布 test1

在這里插入圖片描述

打印臺輸出:

在這里插入圖片描述

此時我們看到 app.envetmsg 里有我們剛訂閱的兩個函數(shù)葵萎。

我們繼續(xù)跳轉 pageC 發(fā)布一條信息:

在這里插入圖片描述

此時打印臺輸出:

在這里插入圖片描述
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市唱凯,隨后出現(xiàn)的幾起案子陌宿,更是在濱河造成了極大的恐慌,老刑警劉巖波丰,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件壳坪,死亡現(xiàn)場離奇詭異,居然都是意外死亡掰烟,警方通過查閱死者的電腦和手機爽蝴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纫骑,“玉大人蝎亚,你說我怎么就攤上這事∠裙荩” “怎么了发框?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長煤墙。 經常有香客問我梅惯,道長,這世上最難降的妖魔是什么仿野? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任铣减,我火速辦了婚禮,結果婚禮上脚作,老公的妹妹穿的比我還像新娘葫哗。我一直安慰自己,他們只是感情好球涛,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布劣针。 她就那樣靜靜地躺著,像睡著了一般亿扁。 火紅的嫁衣襯著肌膚如雪捺典。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天魏烫,我揣著相機與錄音辣苏,去河邊找鬼。 笑死哄褒,一個胖子當著我的面吹牛稀蟋,可吹牛的內容都是我干的。 我是一名探鬼主播呐赡,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼退客,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了链嘀?” 一聲冷哼從身側響起萌狂,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎怀泊,沒想到半個月后茫藏,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡霹琼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年务傲,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片枣申。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡售葡,死狀恐怖,靈堂內的尸體忽然破棺而出忠藤,到底是詐尸還是另有隱情挟伙,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布模孩,位于F島的核電站尖阔,受9級特大地震影響,放射性物質發(fā)生泄漏榨咐。R本人自食惡果不足惜诺祸,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一环葵、第九天 我趴在偏房一處隱蔽的房頂上張望像棘。 院中可真熱鬧充蓝,春花似錦厘熟、人聲如沸伞剑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽越平。三九已至昌跌,卻和暖如春仰禀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蚕愤。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工答恶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留饺蚊,地道東北人。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓悬嗓,卻偏偏與公主長得像污呼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子包竹,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348