自定义事件监听(观察者模式)

143 阅读1分钟

自定义事件监听机制的讲解

<!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>