示例代码:
当单击这个按钮时,就会显示一个显示框。这个操作是通过指定 onClick
特性并将一些 JavaScript 代码作为它的值来定义的。在 HTML 中定义的事件处理程序可以包含要执行的具体动作,也可以调用在页面其他地方定义的脚本:
在这个例子中,单击按钮就会调用 showMessage()
函数。这个函数是在一个独立的 元素中定义的,也可以被包含在一个外部文件中。事件处理程序中的代码在执行时,有权访问全局作用域的任何代码。这样指定事件的特点:
1.这样会创建一个封装着元素属性值的函数:这个函数中有一个局部变量 event
,也就是事件对象。
通过 event
变量,可以直接访问事件对象,可以不用自己定义它,也不用从函数的参数列表中读取。在这个函数内部, this
值等于事件的目标元素,例如:
2.它拓展作用域的方式:这个函数内部,可以像访问局部变量一样访问 document
及该元素本身的成员。这个函数使用 with
像下面这样拓展作用域:
function(){
with(document){
with(this){
//元素属性值
}
}
}
这样,事件处理程序要访问自己的属性就简单很多。下面这行代码与前面的例子效果相同:
如果当前元素是一个表单输入元素,则作用域中还包含访问表单元素(父元素)的入口,这个函数就变成如下所示:
function(){
with(document){
with(this.form){
with(this){
//元素属性值
}
}
}
}
实际上,这样扩展作用域的方式,就是想让事件处理程序无需引用表单元素就能访问其他表单字段。例如:
在这个例子中,单击按钮会显示文本框中的文本。值得注意的是,这里直接引用了 username 元素。
1.存在一个时差问题:因为用户可能会在 HTML 元素一出现在页面上就触发相应的事件,但当时的事件处理程序有可能尚不具备执行条件。但是可以通过将 HTML 事件处理程序封装在一个 try-catch
块中,以便错误不会浮出水面:
2.这样扩展事件处理程序的作用域链在不同浏览器中导致不同结果。不同 JavaScript 引擎遵循的标识符解析规则略有差异,很可能会在访问非限定对象成员时出错。
3.HTML 与 JavaScript 代码紧密耦合。如果要更换事件处理程序,就要更改两个地方:HTML 代码和 JavaScript 代码。
使用 JavaScript 指定事件处理程序,首先必须取得一个要操作的对象的引用;每个元素(包括 window 和 document)都有自己的事件处理程序属性,这些属性通常全部小写;将这种属性的值设置为一个函数,就可以指定事件出来程序。如下所示:
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert("Click");
};
我们通过文档对象取得了一个按钮的引用,然后为它指定了 onclick
事件处理程序,但是注意:在这些代码运行以前不会指定事件处理程序,因此如果这些代码在页面中位于按钮后面,就有可能在一段时间内怎么单击都没有反应。
使用 DOM0 级方法指定的事件处理程序被认为是元素的方法。因此,这时候的事件处理程序是在元素的作用域中运行;也就是说,程序中的this
引用当前的元素。如下例子:
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert (this.id); //"myBtn"
};
单击按钮显示的是元素的 ID,这个 ID是通过 this.id
取得的(实际上可以在事件处理程序中通过this
访问元素的任何属性和方法)。以这种方式添加的时间处理程序会在事件流的冒泡阶段被处理。也可以删除通过 DOM0 级方法指定的事件处理程序。只要将事件处理属性的值设置为 null
即可:
btn.onclick = null; //删除事件处理程序
将事件处理程序设置为null
之后,再点击按钮将不会有任何动作发生。
addEventListener()
和 removeEventListener()
。所有DOM节点中都包含这两个方法,并且他们都接受3个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数若是 true ,表示在捕获阶段调用事件处理程序;如果是 fasle,表示在冒泡阶段调用事件处理程序。要在按钮上为click
事件添加事件处理程序,可以使用下列代码:
var btn = document.getElementById("myBtn");
btn.addEventListenenr("click",function(){
alert(this.id);
},false);
上面的代码为一个按钮添加了onclick
事件,而且该事件会在冒泡阶段被触发(因为最后一个参数是 fasle)。与DOM0 级方法一样,这里添加的事件处理程序也是在其依附的元素的作用域中运行。使用 DOM2 级方法添加事件处理程序的主要好处是可以添加多个事件处理程序。
var btn = document.getElementById("myBtn");
btn.addEventListener("click",function(){
alert(this.id);
},false);
btn.addElementListener("click"),function(){
alert("Hello World!");
}.false);
这里为按钮添加了两个事件处理程序。这两个事件处理程序会按照添加他们的顺序触发,因此首先会显示元素的ID,其次会显示”Hello world”消息。通过addEventListener()
添加的事件处理程序只能使用removeEventListener()
来移除;移除时传入的参数与添加处理程序时使用的参数相同。这就意味着通过addEventListener()
添加的匿名函数将无法移除,如下面的例子所示:
var btn = document.getElement("myBtn");
btn.addEventListener("click",function(){
alert(this.id);
},false);
//这里省略了其他代码
btn.removeEventListener("click",function(){//没有用
alert("this.id");
},false);
在这个例子中,我们使用addEventListener()
添加了一个事件处理程序。虽然调用removeEventListener()
时看似使用了相同的参数,但实际上,第二个参数与传入addEventListener()
中的那一个是完全不同的函数。而传入removeEventListener()
中的事件处理程序必须与传入addEventListener()
中的相同,如下面的例子所示:
var btn = document.getElementById("myBtn");
var handler = funciton(){
alert(this.id);
};
btn.addEventListener("click",handler,false);
//这里省略了其他代码
btn.removeEventListener("click",handler,false); //有效
大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度的兼容各种浏览器。最好只在需要在事件达到目标之前截获它的时候将时间处理程序添加到捕获阶段。如果不是特别需要,不建议在事件捕获阶段注册事件处理程序。
attachEvent()
和 detachEvent()
,这两个方法接受相同的两个参数:事件处理程序名称与事件处理程序函数。由于 IE8 及更早版本只支持事件冒泡,所以通过 attchEvent()
添加的事件处理程序都会被添加到冒泡阶段。代码示例:
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick",function(){
alert("Clicked");
});
注意,attachEvent()
第一个参数是“onclick”,而非 DOM的 addEventListener()
方法中的“click”。
在 IE 中使用 attachEvent()
与使用 DOM0级方法的主要区别在于事件处理程序的作用域。在使用 DOM0 级方法的情况下,事件处理程序会在其所属元素的作用域内运行;在使用 attachEvent()
方法的情况下,事件处理程序会在全局作用域中运行,因此 this 等于 window 。
代码示例:
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick",function(){
alert(this === window);
//true
});
在编写跨浏览器的代码时,牢记这一区别非常重要。与addEventListener()
类似,attachEvent()
方法也可以用来为一个元素添加多个事件程序。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick",function(){
alert("Clicked");
});
document.getElementById("myBtn");
btn.attachEvent("onclick",function(){
alert("Hello world");
});
这里调用了两次attachEvent()
,为同一个按钮添加了两个不同的事件处理程序。不过,与 DOM 方法不同的是,这些事件处理程序不是以添加它们的顺序执行,而是以相反的顺序被触发。单击这个列子中的按钮,首先看到的是“Hello world!”,然后才是“Clicked”。
使用 attachEvent()
添加的事件可以通过detachEvent()
来移除,条件是必须提供相同的参数。与 DOM 方法一样,这也意味着添加的匿名函数将不能被移除。不过,只要能够将对相同函数的引用传给detachEvent()
,就可以移除相应的事件处理程序。
代码示例:
var btn = document.getElementById("myBtn");
var handler = function(){
alert("Clicked");
};
btn.attachEvent("onclick",handler);
//这里省略了其它代码
btn.detachEvent("onclick",handler);
注意:支持 IE 事件处理程序的浏览器有 IE 和 Opera.
为了以跨浏览器的方式处理事件,不少开发人员会使用能够隔离浏览器差异的 JavaScript 库,还有一些开发人员会自己开发最合适的事件处理的方法。要保证处理事件的代码能在大多数浏览器下一致地运行,只需关注冒泡阶段。
第一个要创建的方法是addHandler()
,它的职责是视情况分别使用 DOM0 级方法、DOM2级方法或 IE 方法来添加事件。这个方法属于一个名叫 EventUtil 的对象。addHandler()
方法接受3个参数:要操作的元素、事件名称和事件处理程序函数。
与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 级方法。如果存在 DOM2 级方法,则使用该方法:传入事件类型、事件处理程序函数和第三个参数 false(表示冒泡阶段)。如果存在的是 IE 的方法,则采取第二种方案。注意,为了在 IE8 及更早版本中运行,此时的事件类型必须加上“on”前缀。最后一种可能就是使用 DOM0 级方法(在现代浏览器中,应该不会执行这里的代码)。此时,我们使用的是方括号语法来将属性名指定为事件处理程序,或者将属性设置为 null。
也可以像下面这样使用 EventUtil 对象:
var btn = document.getElementById("myBtn");
var handler = function(){
alert("Clicked");
};
EventUtil.addHandler(btn,"click",handler);
//这里省略了其他代码
EventUtil.removeHandler(btn,"click",handler);
addHandler()
和removeHandler()
没有考虑到所有的浏览器问题,例如在 IE 中的作用域问题。不过,使用它们添加和移除事件处理程序还是足够了。还需注意,DOM0 级对每个事件只支持一个事件处理程序。