微信小程序 > 微信公开课 > 小程序如何在微信小程序里面实现跨页面通信
微信小程序,微信公开课,小程序如何在微信小程序里面实现跨页面通信

小程序如何在微信小程序里面实现跨页面通信

2019-04-03 15:13:30

如何看待微信公开课小程序热门讨论「小程序如何在微信小程序里面实现跨页面通信」
摘要:小程序如何在微信小程序里面实现跨页面通信
展开:我们在处理业务需求的时候,常常会遇到一些情况,在二级或者三级页面进行某些操作或者变更后,需要将结果通知到上级页面去。比如:选择了某些配置项,点击保存后,外部页面能够立即变更在上传头像页面,上传完毕后,外部页面的头像能够立即显示为新头像。所以,这个时候就涉及到如何在页面之间通信的问题了。跨页面通信进一步说其实就是一个程序内部的事件通知机制问题,在其他平台或者OS上都一些相应的实现,比如:iOSSDK自带的NotificationCenterAndroid平台著名的第三方库EventBus目前微信小程序官方SDK还没有提供EventAPI来帮助开发者实现页面间通信,所以我们今天来看看,自己如何实现这样一个简单的小工具。说到这里就不得不说“云梦”的微信小程序版本了,在小程序开始公测后,我们也在第一时间将“云梦”的基本功能移植到了小程序平台上。整个过程相当顺利,除了小程序的IDE还不是太稳定外,基本上没啥大问题。开发过程和ReactNative基本相似,大概一天时间就搞定了。QuickAndDirty我们知道,在小程序里面一个页面的变化,是通过调用setData函数来实现的。所以想做到在二级页面里让一级页面产生变化,最QuickAndDirty的做法就是把一级页面的this传入到二级页面去,这样我们在二级页面调用page1.setData(…)就可以立即引发外部的变化。但是这并不是一个好的方案,不仅产生了页面的耦合,而且也并不能处理复杂的数据逻辑,因为二级页面不并清楚也不应该关心一级页面想怎么处理当前数据。所以二级页面只应该把变更后的数据通知给一级页面即可,至于一级页面是想刷新界面,还是想本地存储或者发起网络通信,别人都不需知晓了。简单的Callback如果只是想把数据通知给外部页面,那应该怎么做呢?我们来看看第二个方案,如果想产生一个通知,这里就需要用到callback机制了。即关心数据变化的页面,注册一个callback函数到一个公共的地方;而数据变更者在变更数据后,将新的数据放入同一个公共的地方;在放入数据时,同时调用这个callback函数,让callback函数实现者接收到这个变化。哪这个公共的地方在哪里呢?第一反应就是app.js里面,因为小程序提供了一个API叫做getApp(),让page初始化时,可以通过以下代码:varappgetApp()来获取app实例,从而实现全局的数据共享,并且微信也很贴心的在Demo代码里面留了一个globalData字段,以暗示开发者这里是可以用来存储全局数据的。App({globalData:{userInfo:null}})基于app.js方案的伪代码如下://app.jsApp({addListener:function(callback){this.callbackcallback;},setChangedData:function(data){this.datadata;if(this.callback!null){this.callback(data);}}})然后我们在一级页面的onLoad中调用addListener://page1.jsvarappgetApp()Page({onLoad:function(){app.addListener(function(changedData){that.setData({data:changedData});});}})在二级页面数据变更的地方调用://page2.jsvarappgetApp()Page({onBtnPress:function(){app.setChangedData(page2data);}})一个基本合格的方案以上就是跨页面通信的最基本原理,不过这也是一个很dirty的方案,因为上面的代码只能支持一种Event的通知,而且也不能针对这个Event添加多个监听者(比如有多个页面需要同时知道某数据变更)。让我们来看看一个基本合格的Event管理器应该具备怎样的能力?支持多种Event的通知支持对某一Event可以添加多个监听者支持对某一Event可以移除某一监听者将Event的存储和管理放在一个单独模块中,可以被所有文件全局引用根据以上的描述,我们来设计一个新的Event模块,对应上面的能力,它应该具有如下三个函数:on函数,用来向管理器中添加一个Event的Callback,且每一个Event必须有全局唯一的EventName,函数内部通过一个数组来保存同一Event的多个Callbackremove函数,用来向管理器移除一个Event的Callbackemit函数,用来触发一个Event我们在小程序的utils目录中,新建一个event.js文件,来作为一个独立的模块,伪代码如下://event.jsvarevents{};functionon(name,callback){varcallbacksevents[name];addToCallbacks(callbacks,callback);}functionremove(name,callback){varcallbacksevents[name];removeFromCallbacks(callbacks,callback);}functionemit(name,data){varcallbacksevents[name];emitToEveryCallback(callbacks,data);}exports.onon;exports.removeremove;exports.emitemit;我们来看看在一二级页面应该如何来使用这个Event模块在二级页面中触发事件://page2.jsvareventrequire(../../utils/event.js);Page({onBtnPress:function(){event.emit(DataChanged,page2data);}});在一级页面的onLoad中监听事件,onUnload中取消监听://page1.jsvareventrequire(../../utils/event.js);Page({onLoad:function(){varthatthis;event.on(DataChanged,function(changedData){that.setData({data:changedData});});},onUnload:function(){event.remove(DataChanged,);}});咦,似乎哪里不对?remove需要接受两个参数,第一个是EventName,第二个是Callback,但是我们的Callback以匿名函数的方式写在了event.on()的调用语句里面好吧,那我们不得不修改一下语句的调用方式://page1.jsvareventrequire(../../utils/event.js);Page({onDataChanged:function(changedData){this.setData({data:changedData})},onLoad:function(){event.on(DataChanged,this.onDataChanged);},onUnload:function(){event.remove(DataChanged,this.onDataChanged);}});这样就OK了么?NONONONO熟悉Javascriptthis这个大坑的朋友们一定会知道,在onDataChanged这个函数中调用的this并不是我们Page中的那个this,所以根本不可能调用到this.setData(.),于是我们用bind大法稍微调整一下:onLoad:function(){event.on(DataChanged,this.onDataChanged.bind(this));}onUnload:function(){event.remove(DataChanged,this.onDataChanged.bind(this));}现在OK了么?NONONONO!如果大伙敲代码试试,就会发现依然还是不行!因为this.onDataChanged.bind(this)会产生一个新的匿名函数,即bind的返回值是一个函数,那么在onLoad和onUnload里面,各自调用了bind大法,从而产生了各自的匿名函数,也就是说event.remove()塞进去的那个函数,并不是event.on()塞进去的那个函数,这样就造成了remove时无法正确匹配。removeFromCallbacks的伪代码大致如下:functionremoveFromCallbacks(callbacks,callback){varnewCallbacks[];for(varitemincallbacks){if(item!callback){newCallbacks.push(item);}}returnnewCallbacks;}所以我们会发现remove传入的callback永远无法在callbacks数组中被匹配到,从而也就无法正确移除了。最终的代码实现当EventName+Callback无法唯一决定需要移除的监听者时,那么自然想到的就是再增加一个key值,我们可以用Page自身的某个特性来做key,比如pagename,新的remove原型如下:functionremove(eventName,pageName,callback);pageName是一个字符串,如果开发者不能做到全局内pagename唯一的话(比如开发者一不小心写错了),那就可能会出现后来监听者冲掉前面监听者的情况,从而造成无法收到通知的bug。所以这里看起来还是用page的this做key比较靠谱,修改后的函数原型如下:functionon(name,self,callback);functionremove(name,self,callback);让我们来看看内部具体怎么实现。以下是一个完整的on函数实现:functionon(name,self,callback){vartuple[self,callback];varcallbacksevents[name];if(Array.isArray(callbacks)){callbacks.push(tuple);}else{events[name][tuple];}}第二行我们将self(即page的this)和callback合并成一个tuple第三行从events容器中,取出该EventName下的监听者数组callbacks如果该数组存在,则将tuple加入数组;如果不存在,则新建一个数组。remove的完整实现:functionremove(name,self){varcallbacksevents[name];if(Array.isArray(callbacks)){events[name]callbacks.filter((tuple){returntuple[0]!self;});}}第二行从events容器中,取出该EventName下的监听者数组callbacks如果callbacks不存在,则直接返回如果存在,则调用callbacks.filter(fn)方法filter方法的含义是通过fn来决定是否过滤掉callbacks中的每一个项。fn返回true则保留,fn返回false则过滤掉。所以我们调用callbacks.filter(fn)后,callbacks中的每一个tuple都会被依次判定。fn的定义为:(tuple){returntuple[0]!self;}tuple中的第一个元素self和remove传入的self相比较,如果不相等则返回true被保留,如果相等则返回false被过滤掉。callbacks.filter(fn)会返回一个新的数组,然后重新写入events[name],最终达到移除callbacks中某一项的逻辑。最后再来看看emit的实现:functionemit(name,data){varcallbacksevents[name];if(Array.isArray(callbacks)){callbacks.map((tuple){varselftuple[0];varcallbacktuple[1];callback.call(self,data);});}}第二行从events容器中,取出该EventName下的监听者数组callbacks如果callbacks不存在,则直接返回如果存在,则调用callbacks.map(fn)方法和filter的用法类似,map函数的作用相当于for循环,依次取出callbacks中的每一个项,然后对其执行fn(tuple),从其名字就可以看出map就是映射变换的意思,将item变换为另外一种东西,这个映射关系就是fn。fn的定义为:(tuple){varselftuple[0];varcallbacktuple[1];callback.call(self,data);}对传入的tuple,分别取出self和callback,然后调用Javascript的call大法:fn.call(this,args)从而最终实现调用到监听者的目的。讲到这里就基本上差不多了,因为Event模块持有了Page的this,所以一定要在Page的Unload函数中调用event.remove(…),不然会造成内存泄露。源代码event.js的完整源代码和Demo请见https://github.com/danneyyang/weappevent原作者:danneyyang
标签:小程序
微信小程序,微信公开课,小程序如何在微信小程序里面实现跨页面通信

「小程序如何在微信小程序里面实现跨页面通信」热门讨论订阅

方法1:微信扫描微信公开课小程序码即可订阅热门讨论「小程序如何在微信小程序里面实现跨页面通信」

方法2:微信搜索微信公开课小程序名称进入,即可订阅热门讨论「小程序如何在微信小程序里面实现跨页面通信」

方法3:微信网页访问即速商店,长按识别微信公开课小程序码即可订阅热门讨论「小程序如何在微信小程序里面实现跨页面通信」

微信公开课小程序热门讨论「小程序如何在微信小程序里面实现跨页面通信」由微信公开课原创摘录于微信小程序商店shop.jisuapp.cn,转载请注明出处。

微信公开课热门讨论「小程序如何在微信小程序里面实现跨页面通信」由微信公开课开发者向微信用户提供,并对本服务内容、数据资料及其运营行为等真实性、合法性及有效性承担全部责任。