导语:本文主要介绍在小程序中,多页面之间如何保持数据同步javascript
在不少的产品中,都会存在跨页面间须要数据同步,以下示例:前端
为了更好的理解该场景,咱们再详细描绘一下:java
动态广场
、我的中心
、个人动态
、动态详情
动态广场
页,请求加载数据,展现动态列表,其中,咱们用绿色内阴影区分该条动态是“个人”,其余未加内阴影的表示是“别人的”;我的中心
页,请求加载数据,展现获赞数量;个人动态
页,请求加载数据,展现个人动态列表;动态详情
页,请求加载数据,进行点赞
操做;个人动态
页,能够看到该条动态点赞状态和数量发生变化,已经同步;我的中心
页,也能够看到获赞数量发生变化,已经同步;动态广场
页,也能够看到对应的一条动态点赞状态和数量发生变化,已经同步;下面咱们来探讨一下这个场景的实现,在此以前,咱们先要了解在点赞时,该场景中各页面的状态及关系。git
如上图所示,当咱们在点赞时,4个页面都已经在是打开的(4个webview
)。当咱们点同意功时,点击左上解返回时,动态详情
页的webview
关掉,直接看到下一层webview
,也就是个人动态
页,这个页面是已经存在的。其余页面也是如此。web
那对于这些已经存在的页面,咱们应该如何同步更新数据呢?小程序
固然,若是比较懒,能够直接在onShow
的时候从新拉数据渲染页面。但显然这是很是低级、不可取也不必的作法。从新拉数据须要耗时,页面从新渲染也会看到闪屏,关键是根本不必从新拉数据,由于数据发生了变化,前端是知道的。框架
因此咱们能够这样作,在动态详情页点同意功时,保存一个数据到全局globalData
中去,回到个人动态页,在onShow
中去检测全局globalData
中是否有点赞变化的数据,有的话,就读取出来去更新相应的动态。ui
// 动态详情页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
}
}
复制代码
这样彷佛能够达到咱们的目的,无请求、纯前端局部更新。this
但这样还存在一个问题,当咱们再退回到我的中心
页时,要检查下获赞数量是否须要更新,以及回到动态广场
页时,也要检查点赞有没有发生变化。但在这两个页面onShow
去判断App.globalData.like
时,都已经检测不到了,由于该数据已经在个人动态
页onShow
中置为null
了。spa
归纳来讲,在点赞时,只生产了一条数据,但有多个消费者,哪一个页面先把数据消费了,其余页面也就没法检测到数据了。
由此,咱们想到那就使用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都可以小程序中体验,项目源码:git.weixin.qq.com/xinyuanliu/…
欢迎交流讨论。
下面是广告时间
尚未看够?知名小程序跨端框架 Taro 的做者,面对面教你使用 React Hooks 来重构你的小程序,让你更加优雅地进行小程序的数据管理,更有小程序云开发,企业级小程序开发实践等硬核内容,要你好看!扫描下方二维码查看具体详情。