事件

JavaScript与HTML之间的交互式通过事件实现的。可以通过监听器来预定事件,以便事件发生时执行相应的代码。

事件流

事件流描述的是从页面中接收事件的顺序。IE和Netscape团队提出了完全相反的事件流的概念。IE的事件流是事件冒泡流(逐级向上),Netscape Communicator的事件流是事件捕获流(逐级向下)。DOM2级事件规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。可以在最后阶段对事件做出响应。

事件处理程序

事件有click/load和mouseover等,事件处理程序的名字以“on”开头。为时间制定处理程序的方式由多种。

HTML事件处理程序

1
<input type="button" value="Click me" onclick="alert('click')" />

缺点:1.存在时差问题,可能导致时间处理程序不能执行。2.这样扩展时间处理程序的作用域链在不同浏览器中可能会导致不同结果。3.HTML与JavaScript代码紧密耦合。

DOM0级事件处理程序

1
2
3
4
5
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert("click");
}
btn.onclick = null; //删除时间处理程序

DOM2级事件处理程序

DOM2级事件定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListenter()和removeEventListener()。使用前者添加的事件,必须使用后者删除。一个事件可以引发多个事件处理程序。

1
2
3
4
5
var btn = document.getElementById("myBtn");
var handler = function(){ alert(this.id); }
btn.addEventListener("click",handler,false); //false表示冒泡阶段调用事件处理程序,true表示捕获阶段
//其他代码
btn.removeEventListener("click",handler,false); //可以。但无法移除匿名程序

IE事件处理程序

IE实现了与DOM中类似的两个方法:attachEvent()和detachEvent()。接收两个参数。事件处理程序添加到冒泡阶段。

1
2
3
4
5
var btn = document.getElementById("myBtn");
var handler = function(){ alert(this.id); }
btn.attachEvent("onclick",handler);
//其他代码
btn.detachEvent("onclick",handler; //移除

跨浏览器的事件处理程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var EventUtil = {
addHandler:functiong(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:functiong(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;
}
}
}

EventUtil.addHandler(btn,"click",handler);

事件对象

在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息。

DOM中的事件对象

兼容DOM的浏览器会将一个event对象传入到事件处理程序中。无论指定事件处理程序时使用什么方法(DOM0或DOM2级),都会传入event对象。event常用的属性方法有:

  • currentTarget:其事件处理程序当前正在处理事件的那个元素,即事件处理程序注册的元素。等同于this。
  • target:事件的目标。最小的直接发生事件的元素。
  • type:事件的类型,即click、mouseover等。
  • prenentDefault():取消特定事件的默认行为,如点击链接导航到其href特性指定的URL
  • stopPropagation():立即停止事件在DOM层次中的传播,即取消进一步的时间捕获或冒泡。

IE中的事件对象

与访问DOM中的event对象不同,要访问IE中的event对象有几种不同的方式,取决于指定事件处理程序的方法。因为事件处理程序的作用域是根据指定它的方式来确定的,所以不能认为this始终等于事件目标,故而,最好使用event.srcElement比较保险。属性有cancelBubble(设为true可以取消事件冒泡)、returnValue(设为false可以取消事件的默认行为)、srcElement(事件的目标,等同于DOM中的target)、type(被触发的事件的类型)。

跨浏览器的事件对象

虽然DOM和IE中的event对象不同,但基于他们之间的相似性依旧可以拿出跨浏览器的方案来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var EventUtil={
addHandler://略
getEvent:function(event){
return event? event:window.event;
},
getTarget:function(event){
return event.target? event.target:event.srcElement;
},
preventDefault:function(event){
if(event.preventDefault){
event.preventDefault();
}else{
event.returnValue = false;
}
},
stopPropagation:function(event){
if(event.stopPropagation){
event.stopPropagation();
}else{
event.cancelBubble = true;
}
}
}

事件类型

Web浏览器中可能发生的事件有很多类型。DOM3级事件规定了一下几类事件:

  • UI事件,当用户与页面上的元素交互时触发。
  • 焦点事件,当元素获得或失去焦点时触发。
  • 鼠标事件,当用户通过鼠标在页面上执行操作时触发。
  • 滚轮事件,当使用鼠标滚轮或类似设备时触发。
  • 文本事件:当用户在文档中输入文本时触发。
  • 键盘事件,当用户通过键盘在页面上执行操作时触发。
  • 合成事件,当为IME(输入法编辑器)输入字符时触发。
  • 变动事件,当底层DOM结构发生变化时触发。

内存和性能

在JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体性能。首先,每个函数都是对象,都会占用内存。其次,必须事先指定所有事件处理程序而导致的DOM访问次数,会延迟整个页面的交互就绪时间。

事件委托

对“事件处理程序过多”的解决方案是事件委托。事件委托利用了事件冒泡,只指定了一个事件处理程序,就可以管理某一类型的所有事件。例如,可以将一个列表的点击事件交给其body元素解决,判断发生事件的元素,再执行相应的操作。

移除事件处理程序

每当将事件处理程序指定给元素时,运行中的浏览器代码与支持页面交互的JavaScript代码之间就会建立一个连接。在不需要的时候移除事件处理程序,也是解决问题的一种方案。

模拟事件

事件经常由用户操作或通过其他浏览器功能来触发,但其实也可以使用JavaScript在任意时刻来触发特定的事件,而此时的事件如同浏览器创建的事件一样。