微信小程式頁面間通訊的5種方式,小程式5種

來源:互聯網
上載者:User

小程式頁面間通訊的5種方式,小程式5種

PageModel(頁面模型)對小程式而言是很重要的一個概念,從app.json中也可以看到,小程式就是由一個個頁面組成的。

如,這是一個常見結構的小程式:首頁是一個雙Tab架構PageA和PageB,子頁面pageB, PageC。

讓我們假設這樣一個情境:首頁PageA有一個飄數,當我們從PageA新開PageC後,做一些操作,再回退到PageA的時候,這個飄數要重新整理。很顯然,這需要在PageC中做操作時,能通知到PageA,以便PageA做相應的聯動變化。

這裡的通知,專業點說就是頁面通訊。所謂通訊,u3認為要滿足下面兩個條件:

  1. 啟用對方的一個方法調用
  2. 能夠向被啟用的方法傳遞資料

本文將根據項目實踐,結合小程式自身特點,就小程式頁面間通訊方式作一個探討與小結。

通訊分類

按頁面層級(或展示路徑)可以分為:

  1. 兄弟頁面間通訊。如多Tab頁面間通訊,PageA,PageB之間通訊
  2. 父路徑頁面向子路徑頁面通訊,如PageA向PageC通訊
  3. 子路徑頁面向父路徑頁面通訊,如PageC向PageA通訊

按通訊時啟用對方方法時機,又可以分為:

  1. 延遲啟用,即我在PageC做完操作,等返回到PageA再啟用PageA的方法調用
  2. 立即啟用,即我在PageC做完操作,在PageC啟用PageA的方法調用

方式一:onShow/onHide + localStorage

利用onShow/onHide啟用方法,通過localStorage傳遞資料。大概邏輯如下

// pageAlet 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'  }); }});
// pageCPage({ doSomething() {  wx.setStorageSync('__data', 'hello from PageC'); }});

優點:實現簡單,容易理解

缺點:如果完成通訊後,沒有即時清除通訊資料,可能會出現問題。另外因為依賴localStorage,而localStorage可能出現讀寫失敗,從面造成通訊失敗

注意點:頁面初始化時也會觸發onShow

方式二:onShow/onHide + 小程式globalData

同方式一一樣,利用onShow/onHide啟用方法,通過讀寫小程式globalData完成資料傳遞

// PageAlet 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'  }); }});
// PageClet 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]); }}
//pageAlet 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'  }); }});
//pageClet 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這個開源庫做為對象監控庫,有興趣的話,可以自己實現一個。

//pageAimport 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'  }); }});
//pageClet 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__; }}
// pageAlet 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  }); }});
//pageClet app = getApp();Page({ doSomething() {  // 見證奇蹟的時刻  app.pages.get('pages/a/a').sayHello('hello u3xyz.com'); }});

優點:一針見血,功能強大,可以向要通訊頁面做你想做的任何事。無需要綁定,訂閱,所以也就不存在重複的情況

缺點:使用了__route__這個hack屬性,可能會有一些風險

以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援幫客之家。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.