自定义事件监听机制的讲解
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 事件监听原理
1.事件池:{
事件名称1:[事件函数1,事件函数2.....],
事件名称2:[事件函数1,事件函数2.....],
}
相当于在我们使用原生js的事件委托时,添加一个"click"事件名称,可以同时执行事件函数,把这些事件与事件对应的函数
组成的像上面的对象称为事件池,事件池就是记录自定义的事件以及对应的事件函数。
2.给事件池添加监听事件以及对应的函数。/相当于addEventListener
为了使用方便,我们在给事件池添加一个事件时,为了避免重复添加同一个事件名称(原因是对象中的属性名是不能重复的,
否则后面添加地事件会把前面的覆盖掉,那么原来添加的该事件名称中的事件函数就会丢失),我们需要判断事件池中是否有
要添加的事件。
3.取消某事件监听。/相当于removeEventListener
把元素的某个事件监听取消掉
4.触发事件池中的某个事件。
给元素添加事件监听,在给需要添加监听的元素条用这个函数就ok。
-->
<script>
//把上述改写为一个ES6的类,为了便于理解后面的内容我们称为 `监听的类`
//需要给某个类添加监听类中的方法时,就从监听类中继承就OK了
class Event {
events = {};//1.事件池
on(eventName, fn) {//2.添加事件监听。//相当于addEventListener
if (!this.events[eventName]) {//判断事件池中是否有该事件名称
this.events[eventName] = [];//没有就在事件池中的添加一个 eventName:[];
}
this.events[eventName].push(fn);//
}
off(eventName, fn) {//3.取消事件监听//相当于removeEventListener
if (this.events[eventName]) {
this.events[eventName] = this.events[eventName].filter(item => (item != fn));
}
}
dispatch(eventName,event) { //4.触发器 调用dispatch(eventName) 时,将相应的函数都执行了//在实例化的类中调用该方法
if (this.events[eventName]) {
this.events[eventName].forEach(item => {
item.call(this,event);//让添加的事件中this指向后面的实例化对象//event,就是后面实例化类实例化时传入的el
});
}
}
}
//this指向问题
//用 实例化的类(继承了Event的子类) 实例化出的 实例化对象.on()-->Event(监听的类)中的dispatch(eventName,event)通过call-
//->添加触发器的实例化的类的this-->实例化对象
//通过这个途径this最终会重新指向 实例化对象
</script>
</body>
</html>