这篇文章主要介绍了微信小程序页面间通信的5种方式,内容挺不错的,现在分享给大家,也给大家做个参考。
PageModel(页面模型)对小程序而言是很重要的一个概念,从app.json中也可以看到,小程序就是由一个个页面组成的。
如上图,这是一个常见结构的小程序:首页是一个双Tab框架PageA和PageB,子页面pageB, PageC。
让我们假设这样一个场景:首页PageA有一个飘数,当我们从PageA新开PageC后,做一些操作,再回退到PageA的时候,这个飘数要刷新。很显然,这需要在PageC中做操作时,能通知到PageA,以便PageA做相应的联动变化。
这里的通知,专业点说就是页面通信。所谓通信,u3认为要满足下面两个条件:
激活对方的一个方法调用
能够向被激活的方法传递数据
本文将根据项目实践,结合小程序自身特点,就小程序页面间通信方式作一个探讨与小结。
通信分类
按页面层级(或展示路径)可以分为:
兄弟页面间通信。如多Tab页面间通信,PageA,PageB之间通信
父路径页面向子路径页面通信,如PageA向PageC通信
子路径页面向父路径页面通信,如PageC向PageA通信
按通信时激活对方方法时机,又可以分为:
延迟激活,即我在PageC做完操作,等返回到PageA再激活PageA的方法调用
立即激活,即我在PageC做完操作,在PageC激活PageA的方法调用
方式一:onShow/onHide + localStorage
利用onShow/onHide激活方法,通过localStorage传递数据。大概逻辑如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | let isInitSelfShow = true ;
Page({
data: {
helloMsg: & #39;hello from PageA'
},
onShow() {
if (isInitSelfShow) return ;
let newHello = wx.getStorageSync(& #39;__data');
if (newHello) {
this .setData({
helloMsg: newHello
});
wx.clearStorageSync(& #39;__data');
}
},
onHide() {
isInitSelfShow = false ;
},
goC() {
wx.navigateTo({
url: & #39;/pages/c/c'
});
}
});
|
1 2 3 4 5 6 | Page({
doSomething() {
wx.setStorageSync(& #39;__data', 'hello from PageC');
}
});
|
优点:实现简单,容易理解
缺点:如果完成通信后,没有即时清除通信数据,可能会出现问题。另外因为依赖localStorage,而localStorage可能出现读写失败,从面造成通信失败
注意点:页面初始化时也会触发onShow
方式二:onShow/onHide + 小程序globalData
同方式一一样,利用onShow/onHide激活方法,通过读写小程序globalData完成数据传递
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | let isInitSelfShow = true ;
let app = getApp();
Page({
data: {
helloMsg: & #39;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: & #39;/pages/c/c'
});
}
});
|
1 2 3 4 5 6 7 8 | let app = getApp();
Page({
doSomething() {
app.$$data.helloMsg = & #39;hello from pageC';
}
});
|
优点:实现简单,实现理解。因为不读写localStorage,直接操作内存,所以相比方式1,速度更快,更可靠
缺点:同方式1一样,要注意globalData污染
方式三:eventBus(或者叫PubSub)方式
这种方式要先实现一个PubSub,通过订阅发布实现通信。在发布事件时,激活对方方法,同时传入参数,执行事件的订阅方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
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]);
}
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | let app = getApp();
Page({
data: {
helloMsg: & #39;hello from PageA'
},
onLoad() {
app.pubSub.on(& #39;hello', (number) => {
this .setData({
helloMsg: & #39;hello times:' + number
});
});
},
goC() {
wx.navigateTo({
url: & #39;/pages/c/c'
});
}
});
|
1 2 3 4 5 6 7 8 9 10 11 12 13 | let app = getApp();
let counter = 0;
Page({
doSomething() {
app.pubSub.emit(& #39;hello', ++counter);
},
off() {
app.pubSub.off(& #39;hello');
}
});
|
缺点:要非常注意重复绑定的问题
方式四:gloabelData watcher方式
前面提到方式中,我们有利用globalData完成通信。现在数据绑定流行,结合redux单一store的思想,如果我们直接watch一个globalData,那么要通信,只需修改这个data值,通过water去激活调用。同时修改的data值,本身就可以做为参数数据。
为了方便演示,这里使用oba这个开源库做为对象监控库,有兴趣的话,可以自己实现一个。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import oba from & #39;../../plugin/oba';
let app = getApp();
Page({
data: {
helloMsg: & #39;hello from PageA'
},
onLoad() {
oba(app.$$data, (prop, newvalue, oldValue) => {
this .setData({
helloMsg: & #39;hello times: ' + [prop, newvalue, oldValue].join('#')
});
});
},
goC() {
wx.navigateTo({
url: & #39;/pages/c/c'
});
}
});
|
1 2 3 4 5 6 7 8 9 | 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__这个属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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__;
}
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | let app = getApp();
Page({
data: {
helloMsg: & #39;hello from PageA'
},
onLoad() {
app.pages.add( this );
},
goC() {
wx.navigateTo({
url: & #39;/pages/c/c'
});
},
sayHello(msg) {
this .setData({
helloMsg: msg
});
}
});
|
1 2 3 4 5 6 7 8 9 10 | let app = getApp();
Page({
doSomething() {
app.pages.get(& #39;pages/a/a').sayHello('hello u3xyz.com');
}
});
|
优点:一针见血,功能强大,可以向要通信页面做你想做的任何事。无需要绑定,订阅,所以也就不存在重复的情况
缺点:使用了__route__这个hack属性,可能会有一些风险
以上就是本文的全部内容,希望对大家的学习有所帮助。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
暂时没有评论,来抢沙发吧~