一、事件
1. 事件流
事件流:描述从页面中接收事件的顺序。
(1)事件冒泡 ⭐️
事件冒泡(event bubbling):事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。
所有现代浏览器都支持事件冒泡。
实现差别:IE5.5 及更早版本中的事件冒泡会跳过<html>元素,IE9、Firefox、Chrome 和 Safari 将事件一直冒泡到 window 对象。
(2)事件捕获
事件捕获(event capturing):不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。
IE9、Safari、Chrome、Opera 和 Firefox 目前都支持这种事件流模型。这些浏览器都是从 window 对象开始捕获事件的。
有特殊需要时再使用事件捕获。
(3)DOM事件流
事件流包括三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。
IE9、Opera、Firefox、Chrome 和 Safari 都支持 DOM 事件流。
2. 事件处理程序
事件处理程序(事件侦听器):响应某个事件的函数,以"on"开头
(1)HTML事件处理程序
某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的 HTML 特性来指定。这个特性的值应该是能够执行的 JavaScript 代码。
<input type="button" value="Click Me" onclick="alert('Clicked')" />
以下字符需要转义:和号(&)、双引号("")、小于号(<) 或大于号(>)。
在 HTML 中定义的事件处理程序可以包含要执行的具体动作,也可以调用在页面其他地方定义的脚本。
<input type="button" value="Click Me" onclick="showMessage()" />
函数中有一个局部变量 event,可以直接访问事件对象。
函数内部,this 值等于事件的目标元素。
<input type="button" value="Click Me" onclick="alert(event.type)">
<input type="button" value="Click Me" onclick="alert(this.value)">
扩展作用域的方式:
函数内部,可以像访问局部变量一样访问 document 及该元素本身的成员。
如果当前元素是一个表单输入元素,则作用域中还会包含访问表单元素(父元素)的入口。
function(){
with(document){
with(this.form){
with(this){
//元素属性值
}
}
}
}
缺点:
1.存在一个时差问题。因为用户可能会在 HTML 元素一出现在页面上就触发相应的事件,但当时的事件处理程序有可能尚不具备执行条件。 – > try-catch
2.这样扩展事件处理程序的作用域链在不同浏览器中会导致不同结果。不同 JavaScript 引擎遵循的标识符解析规则略有差异,很可能会在访问非限定对象成员时出错。
3.HTML 与 JavaScript 代码紧密耦合。如果要更换事件处理程序,就要改动两个地方:HTML 代码和 JavaScript 代码。
结论:许多开发人员摒弃 HTML 事件处理程序,转而使用 JavaScript 指定事件处理程序。
(2)DOM0 级事件处理程序
通过 JavaScript 指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。
每个元素(包括 window 和 document)都有自己的事件处理程序属性,这些属性通常全部小写(onclick),这种属性的值设置为一个函数,就可以指定事件处理程序。
btn.onclick = function(){
alert(this.id);
};
使用 DOM0 级方法指定的事件处理程序,是在元素的作用域中运行,程序中的 this 引用当前元素。
以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。
删除通过 DOM0 级方法指定的事件处理程序:
btn.onclick = null; //删除事件处理程序
(3)DOM2 级事件处理程序
“DOM2 级事件”定义了两个方法,用于处理指定和删除事件处理程序的操作:
addEventListener()
和 removeEventListener()
。
参数:要处理的事件名,作为事件处理程序的函数,一个布尔值 (true在捕获阶段调用事件处理程序,false在冒泡阶段调用事件处理程序)
btn.addEventListener("click", function(){
alert(this.id);
}, false);
btn.addEventListener("click", handler, false);
btn.removeEventListener("click", handler, false);
事件处理程序是在其依附的元素的作用域中运行,this 引用当前元素。
优势:可以添加多个事件处理程序。
注意:
通过 addEventListener() 添加的事件处理程序只能使用 removeEventListener()来移除。
通过 addEventListener() 添加的匿名函数将无法移除。(移除时没有对应的函数名)
大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度地兼容各种浏览器。
浏览器支持:IE9、Firefox、Safari、Chrome 和 Opera。
(4)IE事件处理程序
IE 实现了与 DOM 中类似的两个方法:attachEvent()
和 detachEvent()
。
两个参数:事件处理程序名称,事件处理程序函数。
该方式只会被添加到冒泡阶段(IE8及更早版本只支持事件冒泡)。
btn.attachEvent("onclick", function(){
alert("Clicked");
});
btn.attachEvent("onclick", handler);
btn.detachEvent("onclick", handler);
attachEvent()与DOM方法比较:
- attachEvent() 第一个参数是"onclick",addEventListener() 方法中是"click"。
- 与DOM0级方法主要区别:事件处理程序的作用域。
DOM0级方法,事件处理程序在其所属元素的作用域内运行;attachEvent()方法,事件处理程序会在全局作用域中运行,因此 this 等于 window。 - 也可以用来为一个元素添加多个事件处理程序。
与DOM方法不同,调用两次attachEvent(),这些事件处理程序不是以添加它们的顺序执行,而是以相反的顺序被触发。 - 使用 attachEvent() 添加的事件可以通过 detachEvent() 来移除,同样,添加的匿名函数将不能被移除。
浏览器支持:IE 和 Opera。
(5)跨浏览器的事件处理程序
addHandler()
:视情况分别使用 DOM0 级方法、DOM2 级方法 或 IE 方法来添加事件。
这个方法属于一个 EventUtil 对象(使用这个对象来处理浏览器间的差异)。
3 个参数:要操作的元素,事件名称,事件处理程序函数。
removeHandler()
:移除之前添加的事件处理程序——无论该事件处理程序是采取什么方式添加到元素中的,如果其他方法无效,默认采用 DOM0 级方法。
参数同上。
var EventUtil = {
addHandler: function(element, type, handler){
if (element.addEventListener){
element.addEventListener(type, handler, false);
} else if (element.attachEvent){
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
},
removeHandler: function(element, type, handler){
if (element.removeEventListener){
element.removeEventListener(type, handler, false);
} else if (element.detachEvent){
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
}
};
注意:addHandler() 和 removeHandler() 没有考虑到所有的浏览器问题,例如在 IE 中的作用域问题。不过使用它们添加和移除事件处理程序已经足够。
上一篇:28-JavaScript高级程序设计-DOM2&3范围
下一篇:30-JavaScript高级程序设计-事件对象