#### 背景介绍
在各种小程序中,我们经常会遇到 这种情况
有一个 列表,点击列表中的一项进入详情,详情有个按钮,删除了这一项,这个时候当用户返回到列表页时,
发现列表中的这一项依然存在,这种情况,就是一个 `bug`,也就是数据不同步问题,这个时候测试小姐姐
肯定会找你,让你解决,这个时候,你也许会很快速的解决,但过一会儿,测试小姐姐又来找你说,我打开了
四五个页面更改了用户状态,但我一层一层返回到首页,发现有好几个页面数据没有刷新,也是一个 bug,
这个时候你就犯愁了,怎么解决,常规方法有下面几种
#### 解决方法
1. 将所有请求放到 生命周期 `onShow` 中,只要我们页面重新显示,就会重新请求,数据也会刷新
2. 通过用 `getCurrentPages` 获取页面栈,然后找到对应的 页面实例,调用实例方法,去刷新数据
3. 通过设置一个全局变量,例如 App.globalData.xxx,通过改变这个变量的值,然后在对应 onShow
中检查,如果值已改变,刷新数据
4. 在打开详情页时,使用 redirectTo 而不是 navigateTo,这样在打开新的页面时,会销毁当前页面,
返回时就不会回到这个里面,自然也不会有数据不同步问题
#### 存在的问题
1. 假如我们将 所有 请求放到 onShow 生命周期中,自然能解决所有数据刷新问题,但是 onShow
这个生命周期,有两个问题
第一个问题,它其实是在 onLoad 后面执行的,也就是说,假如请求耗时相同,从它发起请求到页面渲染,
会比 onLoad 慢
第二个问题,那就是页面隐藏、调用微信分享、锁频等等都会触发执行,请求放置于 `onShow` 中就会造成
大量不需要的请求,造成服务器压力,多余的资源浪费、也会造成用户体验不好的问题
2. 通过 `getCurrentPages` 获取页面栈,然后找到对应的 页面实例,调用实例方法,去刷新数据,这也
不失为一个办法,但是就如微信官方文档所说
> 不要尝试修改页面栈,会导致路由以及页面状态错误。
> 不要在 App.onLaunch 的时候调用 `getCurrentPages()`,此时 page 还没有生成。
同时、当需要通信的页面有两个、三个、多个呢,这里去使用 `getCurrentPages` 就会比较困难、繁琐
3. 通过设置全局变量的方法,当需要使用的地方比较少时,可以接受,当使用的地方多的时候,维护起来
就会很困难,代码过于臃肿,也会有很多问题
4. 使用 redirectTo 而不是 navigateTo,从用来体验来说,很糟糕,并且只存在一个页面,对于
tab 页面,它也无能为力,不推荐使用
#### 最佳实践
在 Vue 中, 可以通过 new Vue() 来实现一个 event bus作为事件总线,来达到事件通知的功能,在各大
框架中,也有自身的事件机制实现,那么我们完全可以通过同样的方法,实现一个事件中心,来管理我们的事件,
同时,解决我们的问题。iny-bus 就是这样一个及其轻量的事件库,使用 typescript 编写,100% 测试覆
盖率,能运行 js 的环境,就能使用
传送门
[源码](https://github.com/landluck/iny-bus)
[NPM](https://www.npmjs.com/package/iny-bus)
[文档](https://landluck.github.io/iny-bus/docs/)
#### 简单使用
iny-bus 使用及其简单,在需要的页面 onLoad 中添加事件监听, 在需要触发事件的地方派发事件,使监
听该事件的每个页面执行处理函数,达到通信和刷新数据的目的,在小程序中的使用可以参考以下代码
// 小程序 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 }) // 调用页面请求函数,刷新数据 this .refreshPageData() }) // 添加只需要执行一次的 事件监听 this .eventIdOnce = bus.once( '事件名' , () => { // do some thing }) } // 移除事件监听,该函数有两个参数,第二个事件id不传,会移除整个事件监听,传入ID,会移除该 // 页面的事件监听,避免多余资源浪费, 在添加事件监 /// 听后,页面卸载(onUnload)时建议移除 onUnload () { bus.remove( '事件名' , this .eventId) } // 派发事件,触发事件监听处更新视图 // 支持多参传递 onClick () { bus.emit( '事件名' , a, b, c) } |
更详细的使用和例子可以参考 [Github iny-bus 小程序代码](https://github.com/landluck/iny-bus/tree/master/examples)
#### iny-bus 具体实现
* 基本打包工具,这里使用非常优秀的开源库 [typescript-library-starter](https://github.com/alexjoverm/typescript-library-starter),具体细节不展开
* 测试工具 使用 facebook 的 [jest](https://github.com/facebook/jest)
* build ci 使用 [travis-ci](https://www.travis-ci.org/)
* 测试覆盖率上传使用 [codecov](https://codecov.io/)
* 具体的其他细节大家可以看源码中的 [package.json](https://github.com/landluck/iny-bus/blob/master/package.json),这里就一一展开讲了
iny-bus 的核心代码,其实就这么多,总的来说,非常少,但是能解决我们在小程序中遇到的大量 通信 和 数据刷新问题,是采用 各大平台小程序 原生开发时,页面通信的不二之选,同时,100% 的测试覆盖率,确保了 iny-bus 在使用中的稳定性和安全性,当然,每个库都是从简单走向复杂,功能慢慢完善,如果
大家在使用或者源码中发现了bug或者可以优化的点,欢迎大家提 pr 或者直接联系我
最后,如果 iny-bus 给你提供了帮助或者让你有任何收获,请给 作者 点个赞,感谢大家 [点赞](https://github.com/landluck/iny-bus)
我的是进入详情页传了index,当他删除时 缓存index,还有他的状态,然后跳转到上一页,上一页的onShow里面获取缓存,获取成功后,删除缓存,下标index的数据清空,并且wx:for中的数据 为空时不显示,
感谢分享,目前还是用第二种解决方案
文章提到的问题
其实不会发生,因为我们调用的页面栈中的方法而不是直接修改,所以不会有问题
其次,既然是页面通信,肯定不会存在App.onLaunch去调用的场景
多个页面栈的情况的,的确不好解决,我们的解决方法是框架一开始就通过页面name(自己设置一个以表明是同个页面)记录下来。后面只要循环一下就可以
------
eventBus有好优化,坏处也是不好管理,监听多那个乱得太夸张
----
eventBus的我们一般用的是mitt(https://github.com/developit/mitt)
---
第二种解决方案目前觉得还是最好的,好管理
我是不太建议使用 getCurrentPages 的,原因如下
使用 getCurrentPages,当涉及多个页面,如果使用 name 去循环的话,需要每一个页面提供一个相同的处理函数,如何不同,判断逻辑就有点冗余
同时,开发人员在开发就非常需要去约定相关的内容,需要关心每一个需要刷新的页面,逻辑就耦合了
使用 bus 的话,就不需要关心其他页面的内容,只需要 当前 页面 触发 事件,其他页面监听处理即可,在复用方面也非常简单
而且, getCurrentPages 是无法在同一个页面中的不同组件中使用的,典型的 兄弟组件如何通信,而 bus 是完全能够使用的,这也是 bus 的一大优势
em..
页面提供函数这个本来就该怎么做?
兄弟组件通信肯定也是用triggerEvent和selectComp去处理,这个应该也是和前端框架相同的...
eventBus和提供函数这种方法刚好是反过来的思维,eventBus看似取巧但是实际合作很麻烦,所以我们淘汰了这种方案
其实,小程序自己也搞了eventBus,但是在路由里把eventBus传过去(处理上和提供函数思路是一样的,类似于扩展而不是拿来通信)
在小程序的.js文件中直接引用报错,
import bus from 'iny-bus'
页面【pages/component/my/matchList/matchList]错误:
Error: module 'pages/component/my/matchList/iny-bus.js' is not defined, require args is 'iny-bus'
我按commd+左键可以点进包里面,这是啥问题
感谢大佬感谢大佬感谢大佬感谢大佬感谢大佬感谢大佬感谢大佬感谢大佬感谢大佬感谢大佬感谢大佬感谢大佬感谢大佬感谢大佬感谢大佬感谢大佬
不错的解决方案
微信小程序报错
在 typesrcipt 里面 直接引用不 .js 文件。 使用 npm i iny-bus -save 导入 iny-bus Typescript 使用引入 都报错 import mitt from 'mitt'; const emitter: mitt.Emitter = mitt();
支持用上了
感谢楼主分享,学习了
支持,用上了!