你不知道的JavaScript--Item38自定义事件,JavaScript 自定义事件就是有别于如 click, submit 等标准事件的自行定制的事件,在叙述自定义事件有何好处之前,先来看一个自定义事件的例子:
<p id="testBox"></p> // 创建事件 var evt = document.createEvent('Event'); // 定义事件类型 evt.initEvent('customEvent', true, true); // 在元素上监听事件 var obj = document.getElementById('testBox'); obj.addEventListener('customEvent', function(){ console.log('customEvent 事件触发了'); }, false); //触发--分发事件:注意,监听事件一定要在分发事件之前 obj.dispatchEvent(evt)
在标准浏览器中,自定义事件可以轻松的使用下面的步骤就行:
在这个过程中,createEvent 方法创建了一个空事件 evt,然后使用 initEvent 方法定义事件的类型为约定好的自定义事件,再对相应的元素进行监听,接着,就是使用 dispatchEvent 触发事件了。
没错,自定义事件的机制如普通事件一样——监听事件,写回调操作,触发事件后执行回调。但不同的是,自定义事件完全由我们控制触发时机,这就意味着实现了一种 JavaScript 的解耦。我们可以把多个关联但逻辑复杂的操作利用自定义事件的机制灵活地控制好。
步骤
总的来说就是这三个函数配合使用:
document.createEvent()// 创建 event.initEvent()// 初始化 element.dispatchEvent()// 触发
createEvent()方法返回新创建的Event对象,支持一个参数,表示事件类型,具体见下表:
参数 | 事件接口 | 初始化方法 |
---|---|---|
HTMLEvents | HTMLEvent | initEvent() |
MouseEvents | MouseEvent | initMouseEvent() |
UIEvents | UIEvent | initUIEvent() |
createEvent()方法,创建一个Dom事件。
initEvent()方法用于初始化通过DocumentEvent接口创建的Event的值。支持三个参数:initEvent(eventName, canBubble, preventDefault). 分别表示事件名称,是否可以冒泡,是否阻止事件的默认操作。
dispatchEvent()就是触发执行了,dom.dispatchEvent(eventObject), 参数eventObject表示事件对象,是createEvent()方法返回的创建的Event对象。
当然,可能你已经猜到了,上面的代码在低版本的 IE 中并不生效,事实上在 IE8 及以下版本的 IE 中并不支持 createEvent(),而有 IE 私有的 fireEvent() 方法,但遗憾的是,fireEvent 只支持标准事件的触发。因此,我们只能使用一个特殊而简单的方法触发自定义事件。
由于向下很多版本的浏览器都不支持document.createEvent()方法,因此我们需要另辟蹊径(据说IE有document.createEventObject()和event.fireEvent()方法,但是不支持自定义事件~~)。
IE浏览器有不少自给自足的东西,有个"propertychange“事件,顾名思意,就是属性改变即触发的事件。这里就不细谈,可以查看相应的博客
https://www.zhangxinxu.com/wordpress/2012/04/js-dom%E8%87%AA%E5%AE%9A%E4%B9%89%E4%BA%8B%E4%BB%B6/
https://kayosite.com/javascript-custom-event.html
下面主要讲讲自己要如何去自定义事件?
发布事件其实是指定可用的事件类型列表。当然这个并非一定要实现,类似jQuery方式的也是可行的。
事件类型其实是相当于一个查找key,而这个key可以关联多个函数。所以这个事件类型应该是Map的一个key,这个key被关联到一个待执行函数列表。我们暂且将这个Map定义为eventsList。
事件订阅是往eventsList里添加事件类型key和它所关联的待执行函数。当然如果eventsList里已经存在某个key,则仅仅是将待执行函数添加到队列尾。
事件触发令所指定的事件类型key所关联的待执行函数列表有机会逐一执行。
我们想的是,如何像调用函数一样,依次触发一系列函数,如下面的方式,未完。。。。先睡一觉,明天起来再写~~~~
<p id="p1">p</p> <p id="span1">span</p> <script type="text/javascript"> window.onload = function(){ var p1 = document.getElementById('p1'); var span1 = document.getElementById('span1'); //常规的事件绑定, 直接绑定就能触发,这是符合我们的逻辑 bindEvent(p1, 'click', function(){ alert('1'); }); bindEvent(p1, 'click', function(){ alert('2'); }); //注册事件 bindEvent(span1, 'show', function(){ alert('3'); }); bindEvent(span1, 'show', function(){ alert('4'); }); bindEvent(span1 , 'hide',function(){ alert(5); }); //触发事件 fireEvent(span1, 'show'); }; //监听事件,将事件压入队列 function bindEvent(obj, events, fn){ obj.listeners = obj.listeners || {}; obj.listeners[events] = obj.listeners[events] || []; obj.listeners[events].push(fn); if (obj.addEventListener) { obj.addEventListener(events,fn); }else{ obj.attachEvent("on" + events, fn); } } function fireEvent(obj, events){ for (var i = 0; i < obj.listeners[events].length; i++) { obj.listeners[events][i](); //执行绑定的操作就可以了; }; } </script>