微信小程序页面间通信的5种方式
PageModel(页面模型)对小程序而言是很重要的一个概念,从app.json中也可以看到,小程序就是由一个个页面组成的。 如上图,这是一个常见结构的小程序:首页是一个双Tab框架PageA和PageB,子页面pageB,PageC。 让我们假设这样一个场景:首页PageA有一个飘数,当我们从PageA新开PageC后,做一些操作,再回退到PageA的时候,这个飘数要刷新。很显然,这需要在PageC中做操作时,能通知到PageA,以便PageA做相应的联动变化。 这里的通知,专业点说就是页面通信。所谓通信,u3认为要满足下面两个条件:
本文将根据项目实践,结合小程序自身特点,就小程序页面间通信方式作一个探讨与小结。 通信分类按页面层级(或展示路径)可以分为:
按通信时激活对方方法时机,又可以分为:
方式一:onShow/onHide + localStorage利用onShow/onHide激活方法,通过localStorage传递数据。大概逻辑如下 Page({
data: { helloMsg: 'hello from PageA' },onShow() { // 页面初始化也会触发onShow,这种情况可能不需要检查通信 if (isInitSelfShow) return; let newHello = wx.getStorageSync('__data'); if (newHello) { // 清队上次通信数据 },onHide() { 优点:实现简单,容易理解缺点:如果完成通信后,没有即时清除通信数据,可能会出现问题。另外因为依赖localStorage,而localStorage可能出现读写失败,从面造成通信失败注意点:页面初始化时也会触发onShow方式二:onShow/onHide + 小程序globalData同方式一一样,利用onShow/onHide激活方法,通过读写小程序globalData完成数据传递 Page({
data: { helloMsg: 'hello from PageA' },onShow() { if (isInitSelfShow) return; let newHello = app.$$data.helloMsg; if (newHello) { // 清队上次通信数据 },goC() { Page({
doSomething() { app.$$data.helloMsg = 'hello from pageC'; } }); 优点:实现简单,实现理解。因为不读写localStorage,直接操作内存,所以相比方式1,速度更快,更可靠缺点:同方式1一样,要注意globalData污染方式三:eventBus(或者叫PubSub)方式这种方式要先实现一个PubSub,通过订阅发布实现通信。在发布事件时,激活对方方法,同时传入参数,执行事件的订阅方法 on(type,handler) {
let cache = this.PubSubCache[type] || (this.PubSubCache[type] = {}); handler.$uid = handler.$uid || this.PubSubCache.$uid++; emit(type,...param) { if(!cache) return; for(key in cache) { off(type,handler) { if(handler == null) { for($type in cache) { return !counter && (delete this.PubSubCache[type]); 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' }); } }); Page({
doSomething() { app.pubSub.emit('hello',++counter); },off() { app.pubSub.off('hello'); } }); 缺点:要非常注意重复绑定的问题方式四:gloabelData watcher方式前面提到方式中,我们有利用globalData完成通信。现在数据绑定流行,结合redux单一store的思想,如果我们直接watch一个globalData,那么要通信,只需修改这个data值,通过water去激活调用。同时修改的data值,本身就可以做为参数数据。 为了方便演示,这里使用oba这个开源库做为对象监控库,有兴趣的话,可以自己实现一个。 let app = getApp();
Page({ Page({
doSomething() { app.$$data.helloTimes = ++counter; } }); 优点:数据驱动,单一数据源,便于调试缺点:重复watch的问题还是存在,要想办法避免方式五:通过hack方法直接调用通信页面的方法直接缓存页面PageModel,通信时,直接找到要通信页面的PageModel,进而可以访问通信页面PageModel所有的属性,方法。简直不能太cool,感谢小组内小伙伴发现这么amazing的方式。有人肯定会问了,怎么拿到这个所有的PageModel呢。其它很简单,每个页面有onLoad方法,我们在这个事件中,把this(即些页面PageModel)缓存即可,缓存时用页面路径作key,方便查找。那么页面路径怎么获取呢,答案就是page__route__这个属性 add(pageModel) {
let pagePath = this._getPageModelPath(pageModel); this.$$cache[pagePath] = pageModel; get(pagePath) { delete(pageModel) { _getPageModelPath(page) { Page({
data: { helloMsg: 'hello from PageA' },onLoad() { app.pages.add(this); },goC() { wx.navigateTo({ url: '/pages/c/c' }); },sayHello(msg) { this.setData({ helloMsg: msg }); } }); let app = getApp();
Page({ 优点:一针见血,功能强大,可以向要通信页面做你想做的任何事。无需要绑定,订阅,所以也就不存在重复的情况缺点:使用了__route__这个hack属性,可能会有一些风险以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程之家。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |