這篇文章主要介紹了微信小程式頁間通訊的5種方式,內容挺不錯的,現在分享給大家,也給大家做個參考。
PageModel(頁面模型)對小程式而言是很重要的一個概念,從app.json中也可以看到,小程式就是由一個個頁面組成的。
如上圖,這是一個常見結構的小程式:首頁是一個雙Tab框架PageA和PageB,子頁pageB, PageC。
讓我們假設這樣一個場景:首頁PageA有一個飄數,當我們從PageA新開PageC後,做一些操作,再回退到PageA的時候,這個飄數要刷新。很顯然,這需要在PageC中做操作時,能通知到PageA,以便PageA做相應的連動變化。
這裡的通知,專業點說就是頁面通訊。所謂通信,u3認為要滿足下面兩個條件:
激活對方的一個方法調用
通訊分類
方式一:onShow/onHide localStorage
##利用onShow/onHide啟動方法,透過localStorage傳遞資料。大概邏輯如下
// pageA let isInitSelfShow = true; Page({ data: { helloMsg: 'hello from PageA' }, onShow() { // 页面初始化也会触发onShow,这种情况可能不需要检查通信 if (isInitSelfShow) return; let newHello = wx.getStorageSync('__data'); if (newHello) { this.setData({ helloMsg: newHello }); // 清队上次通信数据 wx.clearStorageSync('__data'); } }, onHide() { isInitSelfShow = false; }, goC() { wx.navigateTo({ url: '/pages/c/c' }); } });
// pageC Page({ doSomething() { wx.setStorageSync('__data', 'hello from PageC'); } });
實作簡單,容易理解
如果完成通訊後,沒有即時清除通訊數據,可能會出現問題。另外因為依賴localStorage,而localStorage可能出現讀寫失敗,從面造成通訊失敗
頁面初始化時也會觸發onShow
#方式二:onShow/onHide 小程式globalData
#同方式一一樣,利用onShow/onHide啟動方法,透過讀寫小程式globalData完成數據傳遞
// 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 }); // 清队上次通信数据 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'; } });
實作簡單,實作理解。因為不讀寫localStorage,直接操作內存,所以相比方式1,速度更快,更可靠
#缺點:同方式1一樣,要注意globalData污染
#方式三:eventBus(或叫PubSub)方式
#這種方式要先實作一個PubSub,透過訂閱發布實作通訊。在發布事件時,啟動對方方法,同時傳入參數,執行事件的訂閱方法
#
/* /plugins/pubsub.js * 一个简单的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'); } });
要非常注意重複綁定的問題
方式四:gloabelData watcher方式
在前面提到方式中,我們有利用globalData完成通訊。現在資料綁定流行,結合redux單一store的思想,如果我們直接watch一個globalData,那麼要通信,只需修改這個data值,透過water去啟動調用。同時修改的data值,本身就可以做為參數資料。
為了方便示範,這裡使用oba這個開源函式庫做為物件監控函式庫,有興趣的話,可以自己實作一個。
//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; } });
資料驅動,單一資料來源,方便調試
缺點:重複watch的問題還是存在,要想辦法避免
方式五:透過hack方法直接呼叫通訊頁面的方法
#直接快取頁面PageModel, 通訊時,直接找到要通信頁面的PageModel,進而可以存取通訊頁面PageModel所有的屬性,方法。簡直不能太cool,感謝小組內小夥伴發現這麼amazing的方式。有人一定會問了,要怎麼拿到這個所有的PageModel呢。它很簡單,每個頁面都有onLoad方法,我們在這個事件中,把this(即些頁面PageModel)緩存即可,緩存時用頁面路徑作key,方便查找。那麼頁面路徑怎麼取得呢,答案就是page__route__這個屬性
// plugin/pages.js // 缓存pageModel,一个简要实现 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) { // 关键点 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() { // 见证奇迹的时刻 app.pages.get('pages/a/a').sayHello('hello u3xyz.com'); } });
一針見血,功能強大,可以向要通信頁面做你想做的任何事。無需要綁定,訂閱,所以也就不存在重複的情況 缺點:使用了__route__這個hack屬性,可能會有一些風險 #以上就是本文的全部內容,希望對大家的學習有所幫助,更多相關內容請關注PHP中文網! 相關推薦: ##
以上是微信小程式中頁間通訊的方式的詳細內容。更多資訊請關注PHP中文網其他相關文章!