react不同组件中方法监听--eventProxy发布-订阅模式
发布日期:2021-05-20 10:06:42
浏览次数:38
分类:技术文章
本文共 6024 字,大约阅读时间需要 20 分钟。
1、需求问题:
在做React-ant-design-mobile
APP项目的时候。当导航栏中的确定重置事件需要刷新列表页。而这两个组件毫无联系。这时候就用到了eventProxy
来监听不同组件的方法函数。
- on、one:on 与 one 函数用于订阅者监听相应的事件,并将事件响应时的函数作为参数,on 与 one 的唯一区别就是,使用 one 进行订阅的函数,只会触发一次,而 使用 on 进行订阅的函数,每次事件发生相应时都会被触发。
- trigger:trigger 用于发布者发布事件,将除第一参数(事件名)的其他参数,作为新的参数,触发使用 one 与 on 进行订阅的函数。
- off:用于解除所有订阅了某个事件的所有函数。
3、首先需要引入eventProxy
文件。
const eventProxy = { onObj: { }, oneObj: { }, on: function (key, fn) { if (this.onObj[key] === undefined) { this.onObj[key] = []; } const args = [].concat(Array.prototype.slice.call(arguments, 1)); for (let i = 0; i < args.length; i++) { this.onObj[key].push(args[i]); } }, one: function (key, fn) { if (this.oneObj[key] === undefined) { this.oneObj[key] = []; } this.oneObj[key].push(fn); }, off: function (key) { this.onObj[key] = []; this.oneObj[key] = []; }, trigger: function () { let key, args; if (arguments.length == 0) { return false; } key = arguments[0]; args = [].concat(Array.prototype.slice.call(arguments, 1)); if (this.onObj[key] !== undefined && this.onObj[key].length > 0) { for (let i in this.onObj[key]) { this.onObj[key][i].call(null, args[i]); } } if (this.oneObj[key] !== undefined && this.oneObj[key].length > 0) { for (let i in this.oneObj[key]) { this.oneObj[key][i].apply(null, args); this.oneObj[key][i] = undefined; } this.oneObj[key] = []; } }};export default eventProxy;
4、使用
- 在需要监听的组件方法中:
import eventProxy from '../../utils/eventProxy'
引入文件- 在需要监听的方法中 我这里是确定事件
queryClick = () => { eventProxy.trigger('query', 'list') this.setState({ visible: false, }) }
- 然后在需要执行相应动作的组件中去使用它
- 在
componentDidMount
中去使用
componentDidMount() { // 清除事件监听 eventProxy.on('query', () => { this.getDynamicsList() }) // eventProxy.on('clear', () => { // this.getDynamicsList() // }) }
使用后一定要在组件卸载的时候清除事件监听
componentWillUnmount = () => { // 清除监听 eventProxy.off('query', ''); }
5、就这样,将不同组件方法和事件联系起来了。
可参考—外观模式
外观模式,是一种相对简单而又无处不在的模式。外观模式提供一个高层接口,这个接口使得客户端或子系统更加方便调用。 用一段再简单不过的代码来表示:
实现一个简单的订阅发布者
观察者模式,定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。 事实上,只要你曾经在DOM节点上绑定过事件函数,那么你就曾经使用过观察者模式了! document.body.addEventListener(‘click’, function () { alert(2); });但是这只是对观察者模式最简单的使用,在很多场景下我们经常会实现一些自定义事件来满足我们的需求。
举个例子: 你去一家公司应聘,谈了一顿下来,hr跟你说:“好了,你回去等通知吧!”。 这个时候,1.你会问公司的电话,然后每天打过去问一遍结果 2.把自己的手机号留给hr,然后等他给你打电话相信很多时候呢,大家都是选择了后者。
万一你每天给hr打电话弄烦他了,或许他本来打算招你的,现在也不再打算再鸟你啦! 那么这个时候,hr就相当于一个发布者,而你就是一个订阅者啦! 好吧,大部分叫你回去等消息的就等于没救啦… 我还遇到过一个如果你没被录取,就连通知都不通知你的公司! 那么一个简单的观察者模式应该怎么实现呢? 要指定一个发布者; 给发布者添加一个缓存列表,用于存放回调函数以便通知订阅者;(这家公司很多人来应聘) 最后发布消息的时候,发布者会遍历这个缓存列表,依次触发里面存放的订阅者回调函数;(你up or 你over)var event = { }; //发布者(hr)event.clietList = []; //发布者的缓存列表(应聘者列表)event.listen = function(fn) { //增加订阅者函数this.clietList.push(fn);};event.trigger = function() { //发布消息函数for (var i = 0; i < this.clietList.length; i++) { var fn = this.clietList[i]; fn.apply(this, arguments);}};event.listen(function(time) { //某人订阅了这个消息console.log('正式上班时间:' + time);});event.trigger('2016/10',yes); //发布消息//输出 正式上班时间:2016/10到这里,我们已经实现了一个最简单的观察者模式了!但是上面的函数其实存在一个问题,那就是发布者没办法选择自己要发布的消息类型!比如这家公司同时在招php,web前端,如果使用上面的函数就没办法区分职位了!只能一次性把全部订阅者都发送一遍消息。对上面的代码进行改写:var event = { }; //发布者(hr)event.clietList = []; //发布者的缓存列表(应聘者列表)event.listen = function(key, fn) { //增加订阅者函数if (!this.clietList[key]) { this.clietList[key] = [];}this.clietList[key].push(fn);};event.trigger = function() { //发布消息函数var key = Array.prototype.shift.call(arguments), fns = this.clietList[key];for (var i = 0; i < fns.length; i++) { var fn = fns[i]; fn.apply(this, arguments);}};event.listen('web前端', fn1 = function(time) { //小强订阅了这个消息。console.log('姓名:小强');console.log('正式上班时间:' + time);});event.listen('web前端', fn2 = function(time) { //大大强订阅了这个消息console.log('姓名:大大强');console.log('正式上班时间:' + time);});//发布者发布消息event.trigger('web前端','小强', '2016/10'); //姓名:小强 正式上班时间:2016/10event.trigger('php','大大强', '2016/15'); //姓名:大大强 正式上班时间:2016/15通过添加了一个key,我们实现了对职位的判断。有了订阅事件,我们怎么能少了取消订阅事件呢?event.remove = function(key, fn) { var fns = this.clietList[key];if (!fns) { return false;}if (!fn) { //如果没有传入fn回调函数,直接取消key对应消息的所有订阅 this.clietList[key] = [];} else { for (var i = 0; i < fns.length; i++) { //遍历回调函数列表 var _fn = fns[i]; if (_fn === fn) { fns.splice(i, 1); //删除订阅者的回调函数 } }}};//这时候必须指定回调函数,否则无法在remove函数中进行对比删除。event.listen('web前端', fn1 = function(time) { //小强订阅了这个消息。console.log('姓名:小强');console.log('正式上班时间:' + time);});event.listen('web前端', fn2 = function(time) { //大大强订阅了这个消息console.log('姓名:大大强');console.log('正式上班时间:' + time);});event.remove('web前端',fn1);//发布者发布消息event.trigger('web前端','2016/10');//输出 姓名:大大强 正式上班时间:2016/10
对上面代码进行改进,创建一个全局对象来实现观察者模式,
使用闭包实现私有变量,仅暴露必须的API给使用者:var event = (function() { var clietList = []; //发布者的缓存列表(应聘者列表)var listen = function(key, fn) { //增加订阅者函数 if (!this.clietList[key]) { this.clietList[key] = []; } this.clietList[key].push(fn);};var trigger = function() { //发布消息函数 var key = Array.prototype.shift.call(arguments), fns = this.clietList[key]; for (var i = 0; i < fns.length; i++) { var fn = fns[i]; fn.apply(this, arguments); }};var remove = function(key, fn) { var fns = this.clietList[key]; if (!fns) { return false; } if (!fn) { //如果没有传入fn回调函数,直接取消key对应消息的所有订阅 this.clietList[key] = []; } else { for (var i = 0; i < fns.length; i++) { //遍历回调函数列表 var _fn = fns[i]; if (_fn === fn) { fns.splice(i, 1); //删除订阅者的回调函数 } } }};return{ listen:listen, trigger:trigger, remove:remove}})();
观察者模式进阶:使用命名空间防止事件名冲突实现先发布后订阅功能[观察者模式引自原作者](https://segmentfault.com/a/1190000023447952)
转载地址:https://blog.csdn.net/weixin_45416217/article/details/107702580 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
留言是一种美德,欢迎回访!
[***.207.175.100]2024年04月25日 06时47分21秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
Nginx源代码分析 - 日志处理
2019-04-27
使Apache实现gzip压缩
2019-04-27
Memcached在大型网站中应用
2019-04-27
Hadoop简要介绍
2019-04-27
squid中的X-Cache和X-Cache-Lookup的意义
2019-04-27
squid 优化指南
2019-04-27
编程方式刷新Squid缓存服务器的五种方法
2019-04-27
centos vnc配置笔记
2019-04-27
Linux服务器网络开发模型
2019-04-27
nginx虚拟目录设置 alias 和 root
2019-04-27
理解http响应头中的Date和Age
2019-04-27
四层和七层负载均衡的区别
2019-04-27
设置Squid Cache_mem大小
2019-04-27
squid日志文件太大,怎样处理?
2019-04-27
让Squid 显示本地时间
2019-04-27
linux mysql 命令 大全
2019-04-27
清除Squid缓存的小工具
2019-04-27
Varnish Cache 3.0.0安装
2019-04-27
深入探讨Varnish缓存命中率
2019-04-27