博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
小程序开发经验:多页面数据同步
阅读量:6684 次
发布时间:2019-06-25

本文共 3764 字,大约阅读时间需要 12 分钟。

导语:本文主要介绍在小程序中,多页面之间如何保持数据同步

在很多的产品中,都会存在跨页面间需要数据同步,如下示例:

为了更好的理解该场景,我们再详细描绘一下:

  1. 本场景包括4个页面:动态广场个人中心我的动态动态详情
  2. 首先,进入动态广场页,请求加载数据,展示动态列表,其中,我们用绿色内阴影区分该条动态是“我的”,其他未加内阴影的表示是“别人的”;
  3. 然后,进入个人中心页,请求加载数据,展示获赞数量;
  4. 点击我的动态,进入我的动态页,请求加载数据,展示我的动态列表;
  5. 点击其中一条动态,进入动态详情页,请求加载数据,进行点赞操作;
  6. 在第5步中,点赞成功后,回退到我的动态页,可以看到该条动态点赞状态和数量发生变化,已经同步;
  7. 再回到到个人中心页,也可以看到获赞数量发生变化,已经同步;
  8. 再回到动态广场页,也可以看到对应的一条动态点赞状态和数量发生变化,已经同步;

下面我们来探讨一下这个场景的实现,在此之前,我们先要了解在点赞时,该场景中各页面的状态及关系。

如上图所示,当我们在点赞时,4个页面都已经在是打开的(4个webview)。当我们点赞成功时,点击左上解返回时,动态详情页的webview关掉,直接看到下一层webview,也就是我的动态页,这个页面是已经存在的。其他页面也是如此。

那对于这些已经存在的页面,我们应该如何同步更新数据呢?

当然,如果比较懒,可以直接在onShow的时候重新拉数据渲染页面。但显然这是非常低级、不可取也没必要的做法。重新拉数据需要耗时,页面重新渲染也会看到闪屏,关键是根本没必要重新拉数据,因为数据发生了变化,前端是知道的。

所以我们可以这样做,在动态详情页点赞成功时,保存一个数据到全局globalData中去,回到我的动态页,在onShow中去检测全局globalData中是否有点赞变化的数据,有的话,就读取出来去更新相应的动态。

// 动态详情页jsonLike() {  ...  success: () => {    App.globalData.like = {      fid: 10001,      likes: 1,      hasLike: true             }  }}// 我的动态页jsonShow() {  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').defaultApp({  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时,注册监听事件(在此以我的动态页为例):

// 我的动态.jsconst 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均可以小程序中体验,项目源码:

欢迎交流讨论。


下面是广告时间

还没有看够?知名小程序跨端框架 Taro 的作者,面对面教你使用 React Hooks 来重构你的小程序,让你更加优雅地进行小程序的数据管理,更有小程序云开发,企业级小程序开发实践等硬核内容,要你好看!扫描下方二维码查看具体详情。

转载于:https://juejin.im/post/5cde98046fb9a07ef90c6833

你可能感兴趣的文章
Confluence 6 修改导航显示选项
查看>>
有hibernate的实体类转化成JSON过滤无干类型
查看>>
Centos+Sersync+inotify实时同步数据文件(一)
查看>>
Windows Live Writer发布多个日志
查看>>
python 线程
查看>>
深入浅出桌面虚拟化存储性能的评估
查看>>
druid 数据库密码加密
查看>>
我的友情链接
查看>>
我的友情链接
查看>>
唾面自干
查看>>
ospf v3
查看>>
ATM程序问题集
查看>>
遭遇ORA-00600: internal error code, arguments: [keltnfy-ldmInit], [46], [1], [], [], [], [], []
查看>>
java Socket 缓冲区与请求的关系
查看>>
Oracle 11gR2 使用 RMAN duplicate from active database 复制数据库
查看>>
自定义view的自定义属性的引用
查看>>
Exchange2013 Server 配置管理(二)
查看>>
基于mysql-mmm实现对mysql replication进行监控和故障迁移
查看>>
Scenario 5 –HP C7000 Virtual Connect SUS A/S Uplinks and LADP-FCoE-vSphere
查看>>
Android Support兼容包详解
查看>>