微信小程式中頁間通訊的方式

不言
發布: 2018-06-26 17:06:39
原創
2811 人瀏覽過

這篇文章主要介紹了微信小程式頁間通訊的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傳遞資料。大概邏輯如下

// 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中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板