简述
此文讨论范围是JavaScript 事件接口,往下浏览器内核原理、事件接口的应用也不在讨论范围之内。
当然整个浏览器事件是一个非常大的章节,我们能讨论的只是一小部分3级DOM事件规范(webkit && Gecko ) ,3级dom事件从逻辑,实现,性能上也是比之前事件机制要优越。
事件是前端开发的核心部分,浏览器事件会分三个章节说明
- 浏览器事件一:事件的基础应用
- 浏览器事件二:浏览器是如何实现事件
- 浏览器事件三:自定义事件
事件的概念
官方有一篇关于浏览器事件的概念,由于鄙人英语太差,不敢翻译,文章传送门
3级dom事件实现基础–EventTarget
我们知道3级dom事件(下面称为3级事件)的核心api 是 addEventListener、removeEventListener、dispatchEvent。这三个方法能从某些对象中(htmlElement,window等)访问。那么就意味着这些方法是绑定再对象上面的。
那么浏览器是怎么实现的呢?
我们在控制台中,从上述对象中能找出被继承带有 add、remove、dispatch方法的对象EventTarget;
document.__proto__.__proto__.__proto__.__proto__ // ==> EventTarget{} object
window.__proto__.__proto__.__proto__ // ==> EventTarget{} object
官方文档对EventTarget的陈述:EventTarget is an interface implemented by objects that can receive events and may have listeners for them. 官方文档传送门
浏览器中对象中实现3级事件,继承EventTarget对象就可以实现。但是我们发现并非对象继承EventTarget就可以把自定义对象加入事件流中;
var customEventObj= function(){};
customEventObj.prototype = new EventTarget();
var my_event = new customEventObj()// 系统抛出 TypeError类型异常
EventTarget只是浏览器的JavaScript接口,这个接口并不面向开发者,整个浏览器事件对象本身并非JavaScript对象,我们无法从JavaScript层面上观察到事件实现的细节。
那我们可以模拟这个接口吗,或者更高级的自定义事情。那当然可以,后面文章将探讨这个问题。
addEventListener方法
我们理解字面的意思,这个方法就是 添加一个事件监听器 的意思,我们向一个对象添加一个监听器,去等待某个事件的触发,当事件触发的时候就,监听会执行回调函数
例:
//绑定一个click事件
document.addEventListener('click',function(){
console.log('document accept click event');
})
当我们任意点击网站可视区域// ==> document accept click event
removeEventListener方法
移除改对象对某个事件的监听;
dispatchEvent方法
按照字面意思理解,dispatchEvent就是分发事件的意思,这里引申一个概念–> 事件类型,我们实质分发的是一个事件类型对象(下面称为event对象,这些对象在JavaScript中 是Event类的子类)。下图是事件类型的结构图
我们会将对应的事件传入 dispatchEvent方法来触发该方法,而dispatch 会把event对象传给回调函数;
实现例子:
document.addEventListener('click',function(){
console.log('document accept click event');
})
var clickEvent = new MouseEvent('click');
document.dispatchEvent(clickEvent); ==> document accept click event
Dom事件流
当事件绑定HtmlElement的时候,事件会有一个传递机制,会回溯dom tree逐级传递。这是一个独立的事件机制。具体的会在基础与应用那一章讲,也会在自定义那章提及如何加入dom事件流中。
参考资料:
Overview_of_Events_and_Handlers
EventTarget
《JavaScript权威指南》 作者:David Flanagan