這篇文章主要介紹了微信小程序頁(yè)面間通信的5種方式,內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。
PageModel(頁(yè)面模型)對(duì)小程序而言是很重要的一個(gè)概念,從app.json中也可以看到,小程序就是由一個(gè)個(gè)頁(yè)面組成的。
如上圖,這是一個(gè)常見(jiàn)結(jié)構(gòu)的小程序:首頁(yè)是一個(gè)雙Tab框架PageA和PageB,子頁(yè)面pageB, PageC。
讓我們假設(shè)這樣一個(gè)場(chǎng)景:首頁(yè)P(yáng)ageA有一個(gè)飄數(shù),當(dāng)我們從PageA新開(kāi)PageC后,做一些操作,再回退到PageA的時(shí)候,這個(gè)飄數(shù)要刷新。很顯然,這需要在PageC中做操作時(shí),能通知到PageA,以便PageA做相應(yīng)的聯(lián)動(dòng)變化。
這里的通知,專業(yè)點(diǎn)說(shuō)就是頁(yè)面通信。所謂通信,u3認(rèn)為要滿足下面兩個(gè)條件:
-
激活對(duì)方的一個(gè)方法調(diào)用
-
能夠向被激活的方法傳遞數(shù)據(jù)
本文將根據(jù)項(xiàng)目實(shí)踐,結(jié)合小程序自身特點(diǎn),就小程序頁(yè)面間通信方式作一個(gè)探討與小結(jié)。
通信分類
按頁(yè)面層級(jí)(或展示路徑)可以分為:
-
兄弟頁(yè)面間通信。如多Tab頁(yè)面間通信,PageA,PageB之間通信
-
父路徑頁(yè)面向子路徑頁(yè)面通信,如PageA向PageC通信
-
子路徑頁(yè)面向父路徑頁(yè)面通信,如PageC向PageA通信
按通信時(shí)激活對(duì)方方法時(shí)機(jī),又可以分為:
-
延遲激活,即我在PageC做完操作,等返回到PageA再激活PageA的方法調(diào)用
-
立即激活,即我在PageC做完操作,在PageC激活PageA的方法調(diào)用
方式一:onShow/onHide + localStorage
利用onShow/onHide激活方法,通過(guò)localStorage傳遞數(shù)據(jù)。大概邏輯如下
// pageA let isInitSelfShow = true; Page({ data: { helloMsg: 'hello from PageA' }, onShow() { // 頁(yè)面初始化也會(huì)觸發(fā)onShow,這種情況可能不需要檢查通信 if (isInitSelfShow) return; let newHello = wx.getStorageSync('__data'); if (newHello) { this.setData({ helloMsg: newHello }); // 清隊(duì)上次通信數(shù)據(jù) wx.clearStorageSync('__data'); } }, onHide() { isInitSelfShow = false; }, goC() { wx.navigateTo({ url: '/pages/c/c' }); } });
// pageC Page({ doSomething() { wx.setStorageSync('__data', 'hello from PageC'); } });
優(yōu)點(diǎn):實(shí)現(xiàn)簡(jiǎn)單,容易理解
缺點(diǎn):如果完成通信后,沒(méi)有即時(shí)清除通信數(shù)據(jù),可能會(huì)出現(xiàn)問(wèn)題。另外因?yàn)橐蕾噇ocalStorage,而localStorage可能出現(xiàn)讀寫(xiě)失敗,從面造成通信失敗
注意點(diǎn):頁(yè)面初始化時(shí)也會(huì)觸發(fā)onShow
方式二:onShow/onHide + 小程序globalData
同方式一一樣,利用onShow/onHide激活方法,通過(guò)讀寫(xiě)小程序globalData完成數(shù)據(jù)傳遞
// PageA let isInitSelfShow = true; let app = getApp(); Page({ data: { helloMsg: 'hello from PageA' }, onShow() { if (isInitSelfShow) return; let newHello = app.$$data.helloMsg; if (newHello) { this.setData({ helloMsg: newHello }); // 清隊(duì)上次通信數(shù)據(jù) app.$$data.helloMsg = null; } }, onHide() { isInitSelfShow = false; }, goC() { wx.navigateTo({ url: '/pages/c/c' }); } });
// PageC let app = getApp(); Page({ doSomething() { app.$$data.helloMsg = 'hello from pageC'; } });
優(yōu)點(diǎn):實(shí)現(xiàn)簡(jiǎn)單,實(shí)現(xiàn)理解。因?yàn)椴蛔x寫(xiě)localStorage,直接操作內(nèi)存,所以相比方式1,速度更快,更可靠
缺點(diǎn):同方式1一樣,要注意globalData污染
方式三:eventBus(或者叫PubSub)方式
這種方式要先實(shí)現(xiàn)一個(gè)PubSub,通過(guò)訂閱發(fā)布實(shí)現(xiàn)通信。在發(fā)布事件時(shí),激活對(duì)方方法,同時(shí)傳入?yún)?shù),執(zhí)行事件的訂閱方法
/* /plugins/pubsub.js * 一個(gè)簡(jiǎn)單的PubSub */ export default class PubSub { constructor() { this.PubSubCache = { $uid: 0 }; } on(type, handler) { let cache = this.PubSubCache[type] || (this.PubSubCache[type] = {}); handler.$uid = handler.$uid || this.PubSubCache.$uid++; cache[handler.$uid] = handler; } emit(type, ...param) { let cache = this.PubSubCache[type], key, tmp; if(!cache) return; for(key in cache) { tmp = cache[key]; cache[key].call(this, ...param); } } off(type, handler) { let counter = 0, $type, cache = this.PubSubCache[type]; if(handler == null) { if(!cache) return true; return !!this.PubSubCache[type] && (delete this.PubSubCache[type]); } else { !!this.PubSubCache[type] && (delete this.PubSubCache[type][handler.$uid]); } for($type in cache) { counter++; } return !counter && (delete this.PubSubCache[type]); } }
//pageA let app = getApp(); Page({ data: { helloMsg: 'hello from PageA' }, onLoad() { app.pubSub.on('hello', (number) => { this.setData({ helloMsg: 'hello times:' + number }); }); }, goC() { wx.navigateTo({ url: '/pages/c/c' }); } });
//pageC let app = getApp(); let counter = 0; Page({ doSomething() { app.pubSub.emit('hello', ++counter); }, off() { app.pubSub.off('hello'); } });
缺點(diǎn):要非常注意重復(fù)綁定的問(wèn)題
方式四:gloabelData watcher方式
前面提到方式中,我們有利用globalData完成通信?,F(xiàn)在數(shù)據(jù)綁定流行,結(jié)合redux單一store的思想,如果我們直接watch一個(gè)globalData,那么要通信,只需修改這個(gè)data值,通過(guò)water去激活調(diào)用。同時(shí)修改的data值,本身就可以做為參數(shù)數(shù)據(jù)。
為了方便演示,這里使用oba這個(gè)開(kāi)源庫(kù)做為對(duì)象監(jiān)控庫(kù),有興趣的話,可以自己實(shí)現(xiàn)一個(gè)。
//pageA import oba from '../../plugin/oba'; let app = getApp(); Page({ data: { helloMsg: 'hello from PageA' }, onLoad() { oba(app.$$data, (prop, newvalue, oldValue) => { this.setData({ helloMsg: 'hello times: ' + [prop, newvalue, oldValue].join('#') }); }); }, goC() { wx.navigateTo({ url: '/pages/c/c' }); } });
//pageC let app = getApp(); let counter = 0; Page({ doSomething() { app.$$data.helloTimes = ++counter; } });
優(yōu)點(diǎn):數(shù)據(jù)驅(qū)動(dòng),單一數(shù)據(jù)源,便于調(diào)試
缺點(diǎn):重復(fù)watch的問(wèn)題還是存在,要想辦法避免
方式五:通過(guò)hack方法直接調(diào)用通信頁(yè)面的方法
直接緩存頁(yè)面PageModel, 通信時(shí),直接找到要通信頁(yè)面的PageModel,進(jìn)而可以訪問(wèn)通信頁(yè)面PageModel所有的屬性,方法。簡(jiǎn)直不能太cool,感謝小組內(nèi)小伙伴發(fā)現(xiàn)這么amazing的方式。有人肯定會(huì)問(wèn)了,怎么拿到這個(gè)所有的PageModel呢。其它很簡(jiǎn)單,每個(gè)頁(yè)面有onLoad方法,我們?cè)谶@個(gè)事件中,把this(即些頁(yè)面PageModel)緩存即可,緩存時(shí)用頁(yè)面路徑作key,方便查找。那么頁(yè)面路徑怎么獲取呢,答案就是page__route__這個(gè)屬性
// plugin/pages.js // 緩存pageModel,一個(gè)簡(jiǎn)要實(shí)現(xiàn) export default class PM { constructor() { this.$$cache = {}; } add(pageModel) { let pagePath = this._getPageModelPath(pageModel); this.$$cache[pagePath] = pageModel; } get(pagePath) { return this.$$cache[pagePath]; } delete(pageModel) { try { delete this.$$cache[this._getPageModelPath(pageModel)]; } catch (e) { } } _getPageModelPath(page) { // 關(guān)鍵點(diǎn) return page.__route__; } }
// pageA let app = getApp(); Page({ data: { helloMsg: 'hello from PageA' }, onLoad() { app.pages.add(this); }, goC() { wx.navigateTo({ url: '/pages/c/c' }); }, sayHello(msg) { this.setData({ helloMsg: msg }); } });
//pageC let app = getApp(); Page({ doSomething() { // 見(jiàn)證奇跡的時(shí)刻 app.pages.get('pages/a/a').sayHello('hello u3xyz.com'); } });
優(yōu)點(diǎn):一針見(jiàn)血,功能強(qiáng)大,可以向要通信頁(yè)面做你想做的任何事。無(wú)需要綁定,訂閱,所以也就不存在重復(fù)的情況
缺點(diǎn):使用了__route__這個(gè)hack屬性,可能會(huì)有一些風(fēng)險(xiǎn)
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,更多相關(guān)內(nèi)容請(qǐng)關(guān)注PHP中文網(wǎng)!
相關(guān)推薦:
以上就是微信小程序中頁(yè)面間通信的方式的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注有卡有網(wǎng)。