### [微信小程序中页面间通信的方式](https://www.prosaas.cn/article/17333) **Published:** 2018-06-26T09:06:39 **Author:** 5201314 **Excerpt:** 这篇文章主要介绍了微信小程序页面间通信的5种方式,内容挺不错的,现在分享给大家,也给大家做个参考。PageMo… 这篇文章主要介绍了微信小程序页面间通信的5种方式,内容挺不错的,现在分享给大家,也给大家做个参考。 PageModel(页面模型)对小程序而言是很重要的一个概念,从app.json中也可以看到,小程序就是由一个个页面组成的。 ![](https://img.php.cn/upload/article/000/000/009/e8ddec34a2c90767d0182a14b38668f8-0.png) 如上图,这是一个常见结构的小程序:首页是一个双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,通过订阅发布实现通信。在发布事件时,激活对方方法,同时传入参数,执行事件的订阅方法 ![](https://img.php.cn/upload/article/000/000/009/e8ddec34a2c90767d0182a14b38668f8-1.gif) /\* /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中文网! 相关推荐: 微信小程序 页面跳转传参的介绍 微信小程序的页面跳转传值的实现 微信小程序 页面跳转和数据传递 以上就是微信小程序中页面间通信的方式的详细内容,更多请关注知企PROSAAS其它相关文章! **Tags:** json, php, this, 事件, 对象, 微信小程序 **Categories:** 后端开发 ---