前言
事件就是用户或浏览器自身执行的某种动作。诸如 click、load 和 mouseover,都是事件的名字。而响应某个事件的函数就叫做事件处理程序(或事件侦听器)。
事件处理程序的名字以 on 开头,因此 click 事件的事件处理程序就是 onclick。为事件指定处理程序的方式有很多种。
HTML 事件处理程序
某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的 HTML 特性来指定。这个特性的值应该是能够执行的 JavaScript 代码。例如:
<input type="button" value="Click Me" onclick="alert('Clicked')" />
这个操作是通过指定 onclick 特性并将一些 JavaScript 代码作为它的值来定义。
注意:由于这个值是 JavaScript 代码,因此不能使用未经转义的 HTML 语法字符。
在 HTML 中定义的事件处理程序可以包含要执行的具体动作,也可以调用在页面其他地方定义的脚本,例如:
<script type="text/avascript">
function showMessage() {
alert("Hello World!");
}
</script>
<input type="button" value="Click Me" onclick="showMessage()" />
事件处理程序中的代码在执行时,有权访问全局作用域终的任何代码。
这样指定事件处理程序有一些独到之处。首先,这样会创建一个封装着元素属性值的函数。这个函数中有一个局部变量 event ,也就是事件对象。
<!-- 输出 "click" -->
<input type="button" value="Click Me" onclick="alert(event.type)">
通过 event 变量,可以直接访问事件对象,不需要自己定义,也不需要从函数的参数列表中读取。在这个函数内部,this 值等于事件的目标元素。例如:
<!-- 输出 "Click Me" -->
<input type="button" value="Click Me" onclick="alert(this.value)">
另外:
在这个函数内部,可以像访问局部变量一样访问 document 及该元素本身的成员。
HTML 事件处理程序的缺点
- 存在一个时差问题,用户可能在 HTML 元素出现后就触发相应的事件,但此时 JavaScript 文件可能尚未解析,可能就会引发错误。(一般用try-catch块解决)
- 另一个缺点就是 HTML 与 JavaScript 代码紧密耦合,如果要更换事件处理程序需要改动两个地方。这也是 HTML 事件处理程序逐渐被放弃的主要原因。
DOM0 级事件处理程序
通过 JavaScript 指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。要使用 JavaScript 指定事件处理程序,首先必须取得一个要操作的对象的引用。
每个元素(包括 window 和 document)都有自己的事件处理程序属性,这些属性通常全部小写,例如 onclick。将这种属性的值设置为一个函数,就可以指定事件处理程序,如下所示:
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert(this.id); // "myBtn"
}
如上,不仅仅是 ID,实际上可以在事件处理程序中通过 this 访问元素的任何属性和方法。以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。
删除 DOM0 级事件处理程序
将事件处理程序属性设置为 null 即可。
btn.onclick = null;
DOM2 级事件处理程序
"DOM2 级事件"定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener( ) 和 removeEventListener( )。
所有的 DOM 节点都包含这两个方法,并且他们都接受三个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后一个布尔值如果是 true,表示在捕获阶段调用事件处理程序;如果是 false,表示在冒泡阶段调用事件处理程序。
例如要在按钮上为 click 事件添加事件处理程序:
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
alert(this.id);
}, false);
btn.addEventListener("click", function(){
alert("Hello World!");
}, false);
与 DOM0 级方法一样,这里添加的事件处理程序也是在其依附的元素的作用域中运行。使用 DOM2 级方法添加事件处理程序的主要好处是可以像上面例子一样添加多个事件处理程序。
通过 addEventListener( ) 添加的事件处理程序只能用 removeEventListener( ) 来移除;移除时传入的参数与添加时参数相同。这也意味着,通过 addEventListener( ) 添加的匿名函数将无法移除(例如上面的例子)。
推荐写法:
var btn = document.getElementById("myBtn");
var handler = function() {
alert(this.id);
}
btn.addEventListener("click", handler, false);
btn.removeEventListener("click", handler, false);
通常情况下,都是将时间处理程序添加到事件流的冒泡阶段,这样可以最大限度的兼容各种浏览器。
IE 事件处理程序
IE 中实现了与 DOM 类似的两个方法:attachEvent( ) 和 detachEvent( )。这两个方法接受相同的两个参数:事件处理程序名称和事件处理程序函数。通过这种方式添加的处理程序都会被添加到冒泡阶段。
注意:
- attachEvent( ) 的第一个参数是 “onclick” 而不是 DOM 的 addEventListener( ) 中的 “click”。
- 在使用 DOM0 级方法的情况下,事件处理程序会在其所属元素的作用域内运行,而通过 attachEvent( ) 方法添加的事件处理程序会在全局作用下运行,因此 this = window。
- 也可以添加多个事件处理程序,但是触发顺序与添加顺序相反。
- 使用 attachEvent( ) 添加的事件处理程序通过 detachEvent( ) 移除,同样,添加的匿名函数无法被移除。
跨浏览器的事件处理程序
要保证处理事件的代码能在大部分浏览器下一致的运行,只需要关注冒泡阶段。
第一个要创建的方法是 addHandler( ),它的职责是视情况分别使用 DOM0 级方法,DOM2 级方法或 IE 方法来添加事件。
这个方法属于一个名叫 EventUtil 的对象,我们将使用这个对象来处理浏览器之间的差异。addHandler( ) 方法接受三个参数:要操作的元素、事件名称和事件处理程序函数。
与之对应的方法是 removeHandler( ),它接受相同的参数。这个方法的职责是移除之前添加的事件处理程序——无论该事件处理程序是采取何种方式添加到元素中的,如果其他方法无效,默认采用 DOM0 级方法。
EventUtil 用法如下:
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;
}
}
};
这两种方法都首先会检测传入的元素中是否存在 DOM2 级方法。如果存在,则使用该方法;如果存在的是 IE 的方法,则采用 IE 的方法。最后一种可能就是使用 DOM0 级方法(为了兼容更早的版本,现代浏览器一般不会执行这里)。
可以这样使用 EventUtil 对象:
var btn = document.getElementById("myBtn");
var handler = function() {
alert("Clicked");
};
EventUtil.addHandler(btn, ,"click", handler);
EventUtil.removeHandler(btn, ,"click", handler);
注意:
- 该方法没有考虑到所有的浏览器问题,比如在 IE 中的作用域问题。
- DOM0 级对每个事件只能添加一个事件处理程序。