小程序页面通信、数据刷新、event bus 解决方案之 iny-bus 2.0 来了

532 阅读6分钟

背景介绍

在很久之前,我在写小程序的时候需要遇到一些问题,为了解决这些问题,便有了 iny-bus 这个库,当时主要解决了那些问题呢,让我们回顾一下并介绍一下 2.0的新功能

存在问题

在各种小程序中,我们经常会遇到这种情况

有一个 列表,点击列表中的一项进入详情,详情有个按钮,删除了这一项,这个时候当用户返回到列表页时, 发现列表中的这一项依然存在,这种情况,就是一个 bug,也就是数据不同步问题,这个时候测试小姐姐 肯定会找你,让你解决,这个时候,你也许会很快速的解决,但过一会儿,测试小姐姐又来找你说,我打开了 四五个页面更改了用户状态,但我一层一层返回到首页,发现有好几个页面数据没有刷新,也是一个 bug, 这个时候你就犯愁了,怎么解决,常规方法有下面几种

解决方法

  1. 将所有请求放到 生命周期 onShow 中,只要我们页面重新显示,就会重新请求,数据也会刷新
  2. 通过用 getCurrentPages 获取页面栈,然后找到对应的 页面实例,调用实例方法,去刷新数据
  3. 通过设置一个全局变量,例如 App.globalData.xxx,通过改变这个变量的值,然后在对应 onShow 中检查,如果值已改变,刷新数据
  4. 在打开详情页时,使用 redirectTo 而不是 navigateTo,这样在打开新的页面时,会销毁当前页面, 返回时就不会回到这个里面,自然也不会有数据不同步问题

存在的问题

  1. 假如我们将 所有 请求放到 onShow 生命周期中,自然能解决所有数据刷新问题,但是 onShow 这个生命周期,有两个问题

    第一: 它其实是在 onLoad 后面执行的,也就是说,假如请求耗时相同,从它发起请求到页面渲染, 会比 onLoad

    第二:那就是页面隐藏、调用微信分享、锁频等等都会触发执行,请求放置于 onShow 中就会造成大量不需要的请求,造成服务器压力,多余的资源浪费、也会造成用户体验不好的问题

  2. 通过 getCurrentPages 获取页面栈,然后找到对应的页面实例,调用实例方法,去刷新数据,这也不失为一个办法,但是还是有限制

    第一: getCurrentPages 无法获取 tabBar 页面,而tabBar 页面是需要刷新和通信的重灾区

    第二: 当需要通信的页面有两个、三个、多个呢,这里去使用 getCurrentPages 就会比较困难、繁琐

  3. 通过设置全局变量的方法,当需要使用的地方比较少时,可以接受,当使用的地方多的时候,维护起来就会很困难,代码过于臃肿,也会有很多问题

  4. 使用 redirectTo 而不是navigateTo,从用来体验来说,很糟糕,并且只存在一个页面,对于tab 页面,它也无能为力,不推荐使用

最佳实践

在 Vue 中, 可以通过 new Vue() 来实现一个 event bus作为事件总线,来达到事件通知的功能,在各大 框架中,也有自身的事件机制实现,那么我们完全可以通过同样的方法,实现一个事件中心,来管理我们的事件, 同时,解决我们的问题。iny-bus 就是这样一个及其轻量的事件库,使用 typescript 编写,100% 测试覆 盖率,能运行 js 的环境,就能使用

安装

方式一. 通过 npm 安装

小程序已经支持使用 npm 安装第三方包,详见 npm 支持

# npm
npm i iny-bus -save

# yarn
yarn add iny-bus --production

方式二. 下载代码

直接通过 git 下载 iny-bus 源代码,并将dist目录 中的 index.js 拷贝到自己的项目中

git clone https://github.com/landluck/iny-bus.git

使用

使用内置方法(2.0 推荐)


  // App、Page、Component 使用方法一致,完全不需要手动去添加监听和移除监听了
  import bus from 'iny-bus'

  // bus.app bus.page bus.component
  const page = bus.page({
    busEvents: {
      // 简单使用
      postMessage(msg) {
        this.setData({
          msg
        })
      },
      // 一次性事件
      postMessageOnce: {
        handler (msg) {
          this.setData({
            msg
          })
        },
        once: true
      }
    },
    onLoad() {
      bus.emit('postMessage', 'hello bus')
      bus.emit('postMessageOnce', 'hello bus once')
    }
  })

  Page(page)

在生命周期中使用(1.0使用 和 2.0完全兼容)


  // 小程序
  import bus from 'iny-bus'

  // 添加事件监听
  // 在 onLoad 中注册, 避免在 onShow 中使用
  onLoad () {
    this.eventId = bus.on('事件名', (a, b, c, d) => {
      // 支持多参数
      console.log(a, b, c, d)

      this.setData({
        a,
        b,
        c
      }
    })
  }

  // 移除事件监听,该函数有两个参数,第二个事件id不传,会移除整个事件监听,传入ID,会移除该页面的事件监听,避免多余资源浪费, 在添加事件监听后,页面卸载(onUnload)时建议移除
  onUnload () {
    bus.remove('事件名', this.eventId)
  }
 
  // 派发事件,触发事件监听处更新视图
  // 支持多参传递
  onClick () {
    bus.emit('事件名', a, b, c)
  }
  
  // 清空所有事件监听
  onClear () {
    bus.clear()
  }
 

借助 iny-bus 小程序webview和原生通信

小程序 webview 和原生页面怎么通信,我相信这是一部分同学遇到的一个很不好处理的问题,那么如何借助 iny-bus 来实现 小程序 webview 和原生页面通信呢

  1. webview 和原生通信要借助 web-view 组件的 bindmessage 方法

  1. 要提前在小程序中内置好 iny-bus 的事件监听
  2. 要在 H5 中使用 wx.miniProgram.postMessage

4. 参考以下代码

  // 小程序 webview
  // web-view 组件的 bindmessage 方法
  onMessage ({ detail: { data } }) {
    for (let i = 0; i < data.length; i++) {
        const event = data[i]
        // 分享事件
        if (event.type === 'share') {
        }
        // 刷新事件
        if (event.type === 'refresh' && event.name) {
          // 派发事件,传递参数
          bus.emit(event.name, event.data)
        }
        // 其它事件
     }
  }
  // H5
  wx.miniProgram.postMessage(
    { 
        type: 'refresh',
        name: 'refreshData',
        data: {
            a: 1
        }
    }
  )

最后

iny-bus 的核心代码,非常少,但是能解决我们在小程序中遇到的大量 通信 和 数据刷新问题,是采用 各大平台小程序 原生开发时,页面通信的不二之选,同时,100% 的测试覆盖率,确保了 iny-bus 在使用中的稳定性和安全性,当然,每个库都是从简单走向复杂,功能慢慢完善,如果 大家在使用或者源码中发现了bug或者可以优化的点,欢迎大家提 pr 或者直接联系我

最后,如果 iny-bus 给你提供了帮助或者让你有任何收获,请给 作者 点个赞,感谢大家 点赞 代码地址