先解释下概念:
事件:事件就是用户或浏览器自身执行的某种动作,eg:click,load,mouseover等。
事件处理程序:响应某个事件的函数就叫做事件处理程序(或事件侦听器),事件处理程序以”on”开头,eg:onclick。
事件流:事件流描述的是从页面接收事件的顺序。
事件流
事件冒泡
概念解释:事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。(由IE最先提出)
所有现代浏览器都支持事件冒泡。
事件捕获
概念解释:事件捕获思的想是不太具体的节点先收到事件,而最具体的节点最后收到事件,其用意在于在事件到达预定目标之前捕获它。(Netscape最先提出)
老版本的浏览器不支持事件捕获,虽然IE9,Chrome,Firefox,Safari,Opera目前支持事件捕获,但不建议使用,如非必须,最好用事件冒泡。
DOM事件流
DOM2级事件规定的事件流包括三个阶段:事件捕获,处于目标阶段和事件冒泡阶段,eg:
单击div元素,在DOM事件流中,实际的目标(div)在捕获阶段不会收到事件,这就是说在捕获阶段,事件从Document->html->body后就停止了;接下来就是目标处理阶段,于是事件在div上发生(这个过程在事件处理中会被看作事件冒泡的一部分);最后,冒泡阶段发生,事件又传播回到文档。
注意:虽然规范要求不会在事件捕获阶段触发事件对象上的事件,但是!现代浏览器都会在事件捕获阶段触发事件对象上的事件。
事件处理程序
DOM0级事件处理程序,就是将一个函数赋值给一个事件处理程序属性。eg:
var btn = document.getElementById("myBtn");
btn.onclick = function() {
alert(this.id); //myBtn
};
在DOM0级事件处理程序中,this引用当前元素,如上例:this引用的就是btn。
若要删除事件处理程序,可以这样:
btn.onclick = null;
“DOM2级事件“定义了两个方法,用添加事件处理程序的addEventListener()和用以删除事件处理程序的removeEventListener()。
所有的DOM节点中都包含这两个方法,并且接受三个参数:要处理的事件名,事件处理程序的函数,以及一个指定处理阶段的布尔值(true表示在事件捕获阶段调用事件处理程序,false表示在事件冒泡阶段调用事件处理程序,默认为false)。
eg:
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function() {
alert("haha");
},false);
使用DOM2级方法添加事件处理程序的好处时可以为一个元素添加多个处理程序,eg:
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function() {
alert("hello");
},false);
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function() {
alert("world");
},false);
通过addEventListener()添加的事件处理程序只能通过removeEventListener()来移除,并且移除时传入的参数必须完全相同。注意!通过addEventListener()添加的匿名函数将无法移除。
eg:
btn.addEventListener("click", function() {
alert("hello");
},false);
是不能通过
btn.removeEventListener("click", function() {
alert("hello");
},false);
来移除的,因为function() {alert("hello");}
在两个方法中是不同的函数。
要这样:
var handler = function() {alert("hello");}
btn.addEventListener("click",handler,false);
btn.removeEventListener("click",handler,false);
才能移除。
IE的事件处理程序
与DOM中类似的两个方法attachEvent()和detachEvent(),由于IE8及更早的版本只支持事件冒泡,所以通过attachEvent()添加的处理程序都会被添加到冒泡阶段。另外,attachEvent()和detachEvent()中的事件形式为onclick,eg:btn.attachEvent(“onclick”,handler,false);而添加的事件处理程序会在全局作用域中运行,因此this指向window;除此之外,通过attachEvent()为同一元素添加的多个事件处理程序会按添加的相反的顺序执行。
接下来封装一个跨浏览器的事件处理程序:
var EventUtil = {
addHandler: function(ele, type, handler) {
if(ele.addEventListener) {
ele.addEventListener(type, handler, false);
}
if(ele.attachEvent) {
ele.attachEvent(type, handler);
} else {
ele["on" + type] = handler;
}
}
removeHandler: function(ele, type, handler) {
if(ele.addEventListener) {
ele.removeEventListener(type, handler, false);
}
if(ele.attachEvent) {
ele.detachEvent(type, handler);
} else {
ele["on" + type] = null;
}
}
}
事件对象
DOM中的事件对象
在触发DOM上某个事件的时,会产生一个事件对象event,这个对象中包含所有与事件有关的信息,包括导致事件的元素,事件类型以及其他与特定事件相关的信息。
属性/方法 | 类型 | 说明 |
---|---|---|
bubbles | Boolean | 表明事件是否冒泡 |
cancelable | Boolean | 是否可以取消事件的默认行为 |
currentTarget | Element | 其事件处理程序当前正在处理的元素 |
defaultPrevented | Boolean | 是否已经调用了preventDefault(),DOM3新增属性 |
detail | Integer | 与事件相关的细节信息 |
eventPhase | Integer | 调用事件处理程序的阶段:1-捕获,2-处理,3-冒泡 |
preventDefault() | Function | 取消事件的默认行为。如果cancelable为true则可以使用 |
stopImmediatePropagation() | Function | 取消事件进一步捕获或冒泡,同时阻止任何事件处理程序被调用(DOM3新增) |
stopPropagation() | Function | 取消事件进一步捕获或冒泡,如果bubbles为true,则可以使用 |
target | Element | 事件目标 |
trusted | Boolean | 表示事件由谁生成,为true表示由浏览器生成,为false表示由开发人员通过JS创建(DOM3新增) |
type | String | 被触发事件的类型 |
view | AbstarctView | 与事件关联的抽象视图。等同于发生事件的window对象 |
以上属性/方法皆为只读。
在事件处理程序内部,this始终等于currentTarget的值,而target则只包含事件的实际目标。eg:
document.body.onclick = function(event){
alert(event.currentTarget === document.body);//true
alert(this === document.body)//true
alert(event.target === document.getElementById("myBtn"))//true
}
注:myBtn是位于body内的一个元素。
IE中的事件对象
访问IE中的event对象有好几种方式,取决于添加事件处理程序的方法。使用DOM0级方法添加事件处理程序时,event作为window的一个属性存在;使用attachEvent添加事件处理程序时,event对象作为一个参数传入,和前面的DOM一样。
属性/方法 | 类型 | 说明 |
---|---|---|
cancelBubble | Boolean | 是否取消冒泡,默认false不取消(和DOM中的stopPropagation()作用相同) |
returnValue | Boolean | 是否取消事件的默认行为,默认true不取消(与preventDefault()作用相同) |
srcElement | Element | 事件目标(与DOM中的target属性相同) |
type | String | 被触发事件的类型 |
事件类型
DOM3中规定的事件类型:
名称 | 说明 |
---|---|
UI事件 | 当用户与页面的元素发生交互时触发 |
焦点事件 | 当元素获得或失去焦点时触发 |
鼠标事件 | 当用户通过鼠标在页面执行操作时触发 |
滚轮事件 | 当用户使用滚轮时触发 |
文本事件 | 当用户在文档中输入文本时触发 |
键盘事件 | 当用户通过键盘在页面执行操作时触发 |
合成事件 | 当为输入法编辑器(IME)输入字符时触发 |
变动事件 | 底层DOM发生变化时触发 |
针对各种事件的详细解释请看《JavaScript高级程序设计第三版》
内存和性能
事件委托
当事件处理程序过多时,可以将事件处理程序注册到他们的父级元素上。
移除事件处理程序
每当将事件处理程序指定给元素时,浏览器中运行的代码与支持页面交互的JS代码就会建立一个连接,这种连接越多,页面执行越慢。所以除了前面的事件委托外,也可以在事件处理程序不需要的时候将其移除。
模拟事件
使用JS创建事件模拟浏览器创建的事件,一般用于测试。
在DOM中使用createEvent(),创建event对象,其接收一个事件类型的字符串作参数。
在IE中使用document.createEventObject(),不接受参数,各种属性需手动添加,最后使用fireEvent(),该方法接收两个参数,一个是事件类型,一个就是前面创建的event对象。
如有遗漏错误之处欢迎指正!