Javascript 事件

事件流

IE事件冒泡流:即事件最开始由最具体的元素接收,然后逐级向上传播至最不具体的那个节点(文档)。
事件捕获流:与事件冒泡流相反,由最不具体的元素接收,传至最具体的元素节点。

事件处理程序

1. HTML事件处理程序
缺点:html和js紧密耦合在一起,js代码和html代码都需要修改
2. DOM0级事件处理程序
方法:把一个函数赋值给一个事件的处理程序属性

1
2
3
4
5
6
7
var btn = document.getElementById('btn');
//指定事件处理程序
btn.onclick=function(){
alert("hello");
}
//取消时,将时间处理程序属性设置为null即可
btn.onclick = null;

作用域:DOM0事件处理程序被认为是元素的方法,所以其作用域为元素的作用域,即this引用当前元素
处理阶段:事件处理程序会在事件流的冒泡阶段被处理。
调用情况:只能绑定一个事件处理函数,后面的会覆盖掉前面的
3. DOM2级事件处理程序
方法:添加事件addEventListener();移除事件removeEventlistener()
三个参数:要注册处理程序的事件类型(不包括前缀‘on’)、事件处理程序函数、布尔值(是否在捕获阶段处理事件,默认false)。

1
2
3
var btn = document.getElementById('btn');
btn.addEventListener('click',showMes,false);//不加on
btn.removeEventListener('click',showMes,false);

作用域:与DOM0级的一样,为元素的作用域,this引用当前元素
处理阶段: DOM2级事件处理程序规定事件流的三个阶段:事件捕获阶段,处于目标阶段,事件冒泡阶段。注意第三个参数,以第三个参数区分捕获阶段处理还是冒泡阶段处理。目前事件捕获只能用于以addEventListener()注册且第三个参数是true的事件处理程序中。
调用情况:同一个事件处理程序可以绑定两次,一次用于事件捕获,一次用于事件冒泡;若绑定的是同一个事件处理程序,并且都为事件冒泡或事件捕获,则只能绑定一次;不同的事件处理函数可以绑定多个,按顺序触发。
4. IE事件处理程序
方法:添加事件attachEvent();移除事件detachEvent()
两个参数:事件类型(加上前缀‘on’)、处理程序函数(因为IE8以及更早的版本只支持事件冒泡,不支持事件捕获)

1
2
3
var btn = document.getElementById('btn');
btn.attachEvent('onclick',showMes);//加上on
btn.detachEvent('onclick',showMes);

作用域: this值为全局(window)对象
调用情况: 允许相同的事件处理程序注册多次,当特定的事件类型发生时,注册函数的调用次数和注册次数一样(匿名函数);同一个事件处理函数只能绑定一次(非匿名函数)

事件对象

在触发DOM上的事件时都会产生一个事件对象event,它包含着所有和事件有关的信息,调用事件处理程序时会把事件对象作为一个参数(有一个例外)。
DOM中的事件对象属性

  • type属性:用于获取事件类型(click…) event.type
  • target属性:触发事件的目标元素,是不变的
  • stopPropagation()方法:阻止事件传播,可以在事件传播期间的任何时间调用。
  • preventDefault()方法:取消事件默认行为

IE中的事件对象属性

  • type属性:用于获取事件类型(click…) event.type
  • srcElement属性:触发事件的目标元素
  • cancleBubble属性:阻止事件传播,因为IE8之前版本不支持事件捕获,所以事件传播即为事件冒泡。设置为true表示阻止冒泡
  • returnValue属性:阻止事件默认行为,设置为false阻止事件默认行为

事件委托

事件的代理是靠事件的冒泡机制实现的。可以避免对特定的每个节点添加事件监听,将事件监听绑定到父元素上。
优点: 1.可以大量节省内存占用,减少事件注册 2.可以实现当新增子对象时无需再次对其绑定事件,对于动态内容尤为合适。

封装事件处理程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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;
}
},
delegateEvent:function(element,tag,eventName,listener){

eventUtil.addHandler(element,eventName,function(event){
var target = event.target || event.srcElement;
if(target.tagName.toLowerCase() == tag.toLowerCase()){
listener.call(target,event);
}
});
},
getEvent:function(event){
var event = event?window.event;
},
getType:function(event){
return event.type;
},
getElement:function(event){
return 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;
}
}
}