详解小程序开发经验:多页面数据同步
导语:本文主要介绍在小程序中,多页面之间如何保持数据同步
在很多的产品中,都会存在跨页面间需要数据同步,如下示例:
为了更好的理解该场景,我们再详细描绘一下:
- 本场景包括4个页面:动态广场、个人中心、我的动态、动态详情
- 首先,进入动态广场页,请求加载数据,展示动态列表,其中,我们用绿色内阴影区分该条动态是“我的”,其他未加内阴影的表示是“别人的”;
- 然后,进入个人中心页,请求加载数据,展示获赞数量;
- 点击我的动态,进入我的动态页,请求加载数据,展示我的动态列表;
- 点击其中一条动态,进入动态详情页,请求加载数据,进行点赞操作;
- 在第5步中,点赞成功后,回退到我的动态页,可以看到该条动态点赞状态和数量发生变化,已经同步;
- 再回到到个人中心页,也可以看到获赞数量发生变化,已经同步;
- 再回到动态广场页,也可以看到对应的一条动态点赞状态和数量发生变化,已经同步;
下面我们来探讨一下这个场景的实现,在此之前,我们先要了解在点赞时,该场景中各页面的状态及关系。
如上图所示,当我们在点赞时,4个页面都已经在是打开的(4个webview)。当我们点赞成功时,点击左上解返回时,动态详情页的webview关掉,直接看到下一层webview,也就是我的动态页,这个页面是已经存在的。其他页面也是如此。
那对于这些已经存在的页面,我们应该如何同步更新数据呢?
当然,如果比较懒,可以直接在onshow的时候重新拉数据渲染页面。但显然这是非常低级、不可取也没必要的做法。重新拉数据需要耗时,页面重新渲染也会看到闪屏,关键是根本没必要重新拉数据,因为数据发生了变化,前端是知道的。
所以我们可以这样做,在动态详情页点赞成功时,保存一个数据到全局globaldata中去,回到我的动态页,在onshow中去检测全局globaldata中是否有点赞变化的数据,有的话,就读取出来去更新相应的动态。
// 动态详情页js onlike() { ... success: () => { app.globaldata.like = { fid: 10001, likes: 1, haslike: true } } } // 我的动态页js onshow() { if(app.globaldata.like !== null) { // 读取globaldata.like数据去更新 this.doupdata() // 特别需要注意,更新完后,需要把globaldata.like清掉,不然下次onshow还会继续走到该逻辑 app.globaldata.like = null } }
这样似乎可以达到我们的目的,无请求、纯前端局部更新。
但这样还存在一个问题,当我们再退回到个人中心页时,要检查下获赞数量是否需要更新,以及回到动态广场页时,也要检查点赞有没有发生变化。但在这两个页面onshow去判断app.globaldata.like时,都已经检测不到了,因为该数据已经在我的动态页onshow中置为null了。
概括来说,在点赞时,只生产了一条数据,但有多个消费者,哪个页面先把数据消费了,其他页面也就无法检测到数据了。
由此,我们想到那就使用eventbus来处理。
首先,我们自己实现一套简单的eventbus。
源码见:
在小程序启动时,初始化eventbus:
const event = require('/util/events.js').default app({ events: null, onlaunch(options) { this.initevents() // dootherthings }, initevents() { this.events = new event() }, emitfeedslike(data) { this.events.emit('feedslike', data) }, emitpublishfeeds(data) { this.events.emit('publishfeeds', data) }, ... }
各个页面在onload时,注册监听事件(在此以我的动态页为例):
// 我的动态.js const app = getapp() page({ data: { list: [] }, onload: function (options) { ... // 监听点赞事件广播 ↓ 重点在这里 ↓ app.events.on('feedslike', data => { console.log('我的动态页面收到点赞变化通知:', data) // 进行更新操作 }) // 监听发布事件广播 ↓ 重点在这里 ↓ app.events.on('publishfeeds', data => { console.log('我的动态页面收到发布动态通知:', data) // 进行更新操作 }) }, ... })
然后在动态点赞时,发出事件通知。(这里一条动态是封装成组件,不属于某一个页面,点赞事件也是封装在组件内)
const app = getapp() component({ properties: {...}, methods: { // 点赞 taplike(e) { let { likes, haslike } = this.data likes += (haslike && -1 || 1) haslike = !haslike this.updatefeeds(likes, haslike).then(() => { this.setdata({ likes, haslike }) // 广播事件 ↓ 重点在这里 ↓ app.emitfeedslike({ uid: this.data.uid, fid: this.data.fid, likes, haslike }) }) }, ... } })
这样,我们便在小程序中实现了一套跨页面数据同步的方案。
直观上这已经非常完美的实现了我们的需求。但在小程序中存在一个与我们常规经验不太一致的地方。那就是页面在关掉后,它里面的对象并没有销毁,这点是因为小程序的逻辑层是共用一个进程。
因此,每次进入页面,都会注册一次监听事件,而退出页面后,该事件并不会销毁。这样的话,多次重复进入页面,就会注册多个重复事件,当事件发生时,就会执行多次响应。请仔细观察下图!
为了避免该现象出现,我们切记要在页面的onunload事件中,主动销毁监听事件。
page({ eventslistener: {}, data: { list: [] }, onload: function (options) { ... // 监听点赞事件广播 ↓ 重点在这里 ↓ this.eventslistener.feedslike = app.events.on('feedslike', data => { console.log('我的动态页面收到点赞变化通知:', data) // 进行更新操作 }) // 监听发布事件广播 ↓ 重点在这里 ↓ this.eventslistener.publishfeeds= app.events.on('publishfeeds', data => { console.log('我的动态页面收到发布动态通知:', data) // 进行更新操作 }) }, ↓ 重点在这里 ↓ onunload() { for (let i in this.eventslistener) { app.events.remove(i, this.eventslistener[i]) } }, ... })
至此,我们在小程序中完美的实现了跨页面/组件、多页面数据同步。
本文研究的demo均可以小程序中体验,项目源码:
以上所述是小编给大家介绍的小程序开发经验:多页面数据同步详解整合,希望对大家有所帮助
上一篇: 微信小程序云开发如何使用npm安装依赖
下一篇: 微信公众号文章中的图片怎么设置分组?