为什么要用到事件监听?
在实际开发过程中,经常会遇到下面这种情况:
某个页面包含Header头部、Nav导航、用户个人信息等。这些模块都要等用户登录之后通过发起Ajax异步请求来获取数据。
如果按照之前的做法,需要我们在Login成功之后的回调函数中调用各个模块获取数据的函数。这样看貌似没有什么问题,但只要页面的模块发生了改变,我们就需要在Login.success()中进行修改。举一个简单的例子:
原来的模块是这个样子的:
![](https://pic2.zhimg.com/80/v2-685af9b48af0aece0d70232a5937d2e1_720w.jpg)
用户登录成功后调用各模块的getData()分别发出异步请求来获取数据。
现在Profile模块被删除,添加一个List模块,那我们就不得不在Login的回调函数中也进行相应的修改。这样各模块就与Login直接发生了强耦合:
![](https://pic1.zhimg.com/80/v2-54d881d0fb7b7e315374ca9a6ba633c4_720w.jpg)
再比如,在做类似百度贴吧发帖这样功能的页面时:在用户提交发帖的表单后,需要刷新帖子的列表。这个时候就要调用列表模块的refresh函数。这个时候如果提交表单的函数没有提供提交成功的回调函数的话,我们就无法判断用户什么时候提交了表单。
针对这个问题,就出现了事件监听这一解决方案。使用事件监听机制后,我们只需要在Login的回调函数中发布一个事件。相应的,我们只需要在模块初始化时让模块订阅相应的事件即可。在事件触发后,就会调用模块提供的函数。
![](https://pic2.zhimg.com/80/v2-d402096cdea51f7ecad130deb0077f9d_720w.jpg)
这个其实就是JavaScript中的发布-订阅模式,又叫做观察者模式。利用这一模式我们就可以来实现一个简单的事件监听框架。
代码实现:
核心代码
__Core对象为框架的核心代码。其中__List数组用于存储事件名和对应的函数。
![](https://pic4.zhimg.com/80/v2-af7ed137c13c1eb41c8f836ceb1cf4db_720w.jpg)
subscribe函数:
![](https://pic4.zhimg.com/80/v2-366170cceeb946d2f9b034a18d4aa303_720w.jpg)
函数接收两个参数,事件名,事件触发后的函数。subscribe函数负责将提供的函数存放到对应的事件数组中。
publish函数:
![](https://pic2.zhimg.com/80/v2-30ae8b47ba85dd1c98978662d35b82b5_720w.jpg)
考虑到某个模块可能会触发多个事件,这里通过使Array.prototype.slice.call(arguments)来收集参数,即发布的事件名。通过遍历事件名对应的函数数组并执行对应的函数来达到“广播”的效果。
unsubscribe函数:
![](https://pic2.zhimg.com/80/v2-b874358144c0d05b03f39e791bbedb31_720w.jpg)
模块还可以取消订阅。函数接收两个参数,取消订阅的事件名、对应的函数。若不传入函数,则默认清除事件对应的所有函数。
整体框架:
![](https://pic3.zhimg.com/80/v2-41d714dca0140345c8b766589ea64e02_720w.jpg)
出于框架兼容度的考虑,这里的写法参考了JQuery的源码,利用了闭包函数的特性创建了一个安全的作用域。代码刚开始会通过是否存在window对象来判断运行环境是否为浏览器。如果进入if语句,则为非浏览器环境,为factory添加一个true参数。若存在这一参数则不会为全局的window对象添加Events对象。
代码总览:
![](https://pic3.zhimg.com/80/v2-f85ef4e1e6a27f009af433ea2c52d98a_720w.jpg)
原生Demo:
![](https://pic1.zhimg.com/80/v2-b54573fa06b612f4d3384edc18513a9c_720w.jpg)
效果浏览:
点击前:
![](https://pic2.zhimg.com/80/v2-f3761dfd21b0ae9c017230b0a9deeedd_720w.png)
点击后:
![](https://pic1.zhimg.com/80/v2-bc58f5056efca0ef943597a23ed29b00_720w.png)
参考资料:
javascript中的发布者与订阅者_duanshilong的博客-CSDN博客_发布者订阅者源代码:
syk2018/Events-listener