背景介绍
在很久之前,我在写小程序的时候需要遇到一些问题,为了解决这些问题,便有了 iny-bus
这个库,当时主要解决了那些问题呢,让我们回顾一下并介绍一下 2.0的新功能
存在问题
在各种小程序中,我们经常会遇到这种情况
有一个 列表,点击列表中的一项进入详情,详情有个按钮,删除了这一项,这个时候当用户返回到列表页时,
发现列表中的这一项依然存在,这种情况,就是一个 bug
,也就是数据不同步问题,这个时候测试小姐姐
肯定会找你,让你解决,这个时候,你也许会很快速的解决,但过一会儿,测试小姐姐又来找你说,我打开了
四五个页面更改了用户状态,但我一层一层返回到首页,发现有好几个页面数据没有刷新,也是一个 bug
,
这个时候你就犯愁了,怎么解决,常规方法有下面几种
解决方法
将所有请求放到 生命周期 `` onShow `` 中,只要我们页面重新显示,就会重新请求,数据也会刷新
通过用 `` getCurrentPages `` 获取页面栈,然后找到对应的 页面实例,调用实例方法,去刷新数据
通过设置一个全局变量,例如 `` App.globalData.xxx ``,通过改变这个变量的值,然后在对应 `` onShow ``
中检查,如果值已改变,刷新数据
在打开详情页时,使用 `` redirectTo `` 而不是 `` navigateTo ``,这样在打开新的页面时,会销毁当前页面,
返回时就不会回到这个里面,自然也不会有数据不同步问题
存在的问题
假如我们将 所有 请求放到 `` onShow `` 生命周期中,自然能解决所有数据刷新问题,但是 `` onShow `` 这个生命周期,有两个问题
第一: 它其实是在 `` onLoad `` 后面执行的,也就是说,假如请求耗时相同,从它发起请求到页面渲染,
会比 `` onLoad `` 慢
第二:那就是页面隐藏、调用微信分享、锁频等等都会触发执行,请求放置于 `` onShow `` 中就会造成大量不需要的请求,造成服务器压力,多余的资源浪费、也会造成用户体验不好的问题
通过 `` getCurrentPages `` 获取页面栈,然后找到对应的页面实例,调用实例方法,去刷新数据,这也不失为一个办法,但是还是有限制
第一: `` getCurrentPages `` 无法获取 `` tabBar `` 页面,而`` tabBar `` 页面是需要刷新和通信的重灾区
第二: 当需要通信的页面有两个、三个、多个呢,这里去使用 `` getCurrentPages `` 就会比较困难、繁琐
通过设置全局变量的方法,当需要使用的地方比较少时,可以接受,当使用的地方多的时候,维护起来就会很困难,代码过于臃肿,也会有很多问题
使用 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
和原生页面通信呢
- webview 和原生通信要借助 web-view 组件的 bindmessage 方法
- 要提前在小程序中内置好
iny-bus
的事件监听 - 要在
H5
中使用wx.miniProgram.postMessage
- 参考以下代码
// 小程序 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 或者直接联系我