javascript事件

JavaScript与HTML的交互是通过事件实现的,事件就是文档或浏览器窗口中发生的一些特定的交互瞬间,是用户或浏览器自身执行的某种动作,例如click,mouseover等都是事件名。

(一)事件流

事件流描述的是从页面中接收事件的顺序。

1)事件冒泡

IE中的事件流叫做事件冒泡,即事件开始是由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。如下例1.1所示:

  1. <html>  
  2. <head>  
  3.     <title> Event Bubbling Example </title>  
  4. </head>  
  5. <body>  
  6.     <div id="myDiv">Click Me</div>  
  7. </body>  
  8. </html>  
<html>
<head>
	<title> Event Bubbling Example </title>
</head>
<body>
	<div id="myDiv">Click Me</div>
</body>
</html>


若单击<div>元素,那么click事件会按照如下顺序传播:

a)<div>

b)<body>

c)<html>

d)<document>

click事件会在<div>元素上发生,然后沿着DOM树向上传播,在每一级节点上都发生,直到传播到document对象。如下图所示:

所有现代浏览器都支持事件冒泡,但有区别。IE5.5及更早的版本的事件冒泡跳过<html>元素,直接从<body>到<document >,Firefox、Chrome和Safari则将事件一直冒泡到window对象。下面为一个事件冒泡实例,使用jQuery实现:

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
  2. <html xmlns="http://www.w3.org/1999/xhtml">  
  3. <head>  
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
  5. <title>Event Bubbling Example</title>  
  6. <style type="text/css">  
  7. *{margin:0;padding:0;}    
  8. body { font-size: 13px; line-height: 130%; padding: 60px; }  
  9. #content {  220px; border: 1px solid #0050D0;background: #96E555 }  
  10. span {  200px; margin: 10px; background: #666666; cursor: pointer;color:white;display:block;}  
  11. p {200px;background:#888;color:white;height:16px;}  
  12. </style>  
  13. <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.0/jquery.min.js" type="text/javascript"></script>  
  14. <script type="text/javascript">  
  15. $(function(){  
  16.     // 为span元素绑定click事件  
  17.     $('span').bind("click",function(){  
  18.         var txt = $('#msg').html() + "<p>内层span元素被点击.<p/>";  
  19.         $('#msg').html(txt);  
  20.     });  
  21.     // 为div元素绑定click事件  
  22.     $('#content').bind("click",function(){  
  23.         var txt = $('#msg').html() + "<p>外层div元素被点击.<p/>";  
  24.         $('#msg').html(txt);  
  25.     });  
  26.     // 为body元素绑定click事件  
  27.     $("body").bind("click",function(){  
  28.         var txt = $('#msg').html() + "<p>body元素被点击.<p/>";  
  29.         $('#msg').html(txt);  
  30.     });  
  31. })  
  32. </script>  
  33. </head>  
  34. <body>  
  35. <div id="content">  
  36.     外层div元素  
  37.     <span>内层span元素</span>  
  38.     外层div元素  
  39. </div>  
  40.   
  41. <div id="msg"></div>  
  42. </body>  
  43. </html>  
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Event Bubbling Example</title>
<style type="text/css">
*{margin:0;padding:0;}	
body { font-size: 13px; line-height: 130%; padding: 60px; }
#content {  220px; border: 1px solid #0050D0;background: #96E555 }
span {  200px; margin: 10px; background: #666666; cursor: pointer;color:white;display:block;}
p {200px;background:#888;color:white;height:16px;}
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.0/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
	// 为span元素绑定click事件
	$('span').bind("click",function(){
		var txt = $('#msg').html() + "<p>内层span元素被点击.<p/>";
		$('#msg').html(txt);
	});
	// 为div元素绑定click事件
	$('#content').bind("click",function(){
	    var txt = $('#msg').html() + "<p>外层div元素被点击.<p/>";
		$('#msg').html(txt);
	});
	// 为body元素绑定click事件
	$("body").bind("click",function(){
		var txt = $('#msg').html() + "<p>body元素被点击.<p/>";
		$('#msg').html(txt);
	});
})
</script>
</head>
<body>
<div id="content">
	外层div元素
	<span>内层span元素</span>
	外层div元素
</div>

<div id="msg"></div>
</body>
</html>

单击最内层<span>元素时,显示结果如下:

2)事件捕获

事件捕获的思想是不太具体的节点应该更早接收事件,而最具体的节点应该最后接收到事件。事件捕获的用意在于事件到达预定目标之前捕获它。在例1.1中,那么单击<div>元素会以下列顺序触发click事件:

a)document

b)<html>

c)<body>

d)<div>

事件捕获中,document对象首先接收到click事件,然后沿着DOM树依次向下,一直传播到事件的实际目标,即<div>元素。如下图所示:

3)DOM事件流

“DOM2级事件”规定了事件流的三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。例1.1中单击<div>元素会按照下图触发事件:

在DOM事件流中,实际的目标(<div>元素)在捕获阶段不会接收事件。在捕获阶段,事件从document到<html>再到<body>后就停止了;下一个阶段是“处于目标”阶段,于是事件在<div>上发生,并在事件处理中被看成冒泡的一部分;然后是冒泡阶段,事件又传播回文档。

除了IE不支持DOM事件流,其余四大主流浏览器都支持。

(二)事件处理程序

响应某个事件的函数就叫做事件处理程序,或称为事件侦听器。事件处理程序都是以"on"开头的。例如onclick、onload事件。

下面介绍为事件指定处理程序的几种方法:

1)HTML事件处理程序

某个元素支持每种事件,都可以使用一个与相应事件处理程序同名的HTML特性表示。该特性的值是能够执行的JavaScript代码。如下例所示:

  1. <input type="button" value="Click Me" onclick="alert('Clicked')"/>  
<input type="button" value="Click Me" onclick="alert('Clicked')"/>

也可以使用下述方法,先定义事件处理程序执行的具体动作:

  1. <script type="text/javascript">     
  2.     function showMessage(){  
  3.         alert("hello world!");  
  4.     }  
  5. </script>  
  6. <input type="button" value="Click Me" onclick=" showMessage()" />  
<script type="text/javascript">	
	function showMessage(){
		alert("hello world!");
	}
</script>
<input type="button" value="Click Me" onclick=" showMessage()" />

事件处理程序也可以被包含在独立的外部文件中,事件处理程序中的代码在执行时,有权利访问全局作用域中的任何代码。

HTML事件处理程序缺点:

a)时差问题。用户可能在HTML元素一出现就触发相应事件,而此时事件处理程序有可能还不具备执行条件。

上例中若showMessage()函数在按钮的下方,页面的最底部定义时,若用户在解析showMessage()函数之前就单击按钮,就会引发错误。需将事件错误处理程序放在一个try-catch块中。

  1. <input type="button" value="Click Me" onclick="try{showMessage();} catch(ex){}"/>  
<input type="button" value="Click Me" onclick="try{showMessage();} catch(ex){}"/>

b)HTML与JS代码紧密耦合。

2)DOM0级事件处理程序

通过js指定事件处理程序的传统方法,就是将一个函数赋值给一个事件处理程序的属性。该方法比较简单,而且具有跨浏览器的优势。

在使用js指定事件处理程序时,需要指定一个操作对象的引用。每个元素(包括window和document)都有自己的事件处理程序属性,属性通常全部小写,例如onclick。

[javascript] view plain copy
 
print?
  1. var btn=document.getElementById("myBtn");  
  2. btn.onclick=function(){  
  3.     alert("Clicked");  
  4. };  
var btn=document.getElementById("myBtn");
btn.onclick=function(){
    alert("Clicked");
};

该方法指定的事件处理程序被认为是元素的方法,在元素的作用域中运行的。

[javascript] view plain copy
 
print?
  1. var btn=document.getElementById("myBtn");  
  2. btn.onclick=function(){  
  3.     alert(this.id);  //"myBtn"  
  4. };  
var btn=document.getElementById("myBtn");
btn.onclick=function(){
    alert(this.id);  //"myBtn"
};

可以在任何事件处理程序中通过this访问元素的任何属性和方法。以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。

也可以删除DOM0级方法中指定的事件处理程序。

[javascript] view plain copy
 
print?
  1. btn.onclick=null;  //删除事件处理程序  
btn.onclick=null;  //删除事件处理程序

HTML事件处理程序中。onclick属性就是一个包含着同名HTML特性中指定的代码的函数,也可设置相应的属性为null,删除这种指定的事件处理程序。

3)DOM2级事件处理程序

定义两种方法用于指定和删除事件处理程序的操作:addEventListener()和removeEventListener()。

这两种方法介绍三个参数:要处理的事件名,作为事件处理程序的函数和一个布尔值。

布尔值为true表示在捕获阶段调用事件处理程序,如果为false表示在冒泡阶段调用事件处理程序。如下例所示:

a)addEventListener()

[javascript] view plain copy
 
print?
  1. var btn=document.getElementById("myBtn");  
  2. btn.addEventListener("click",function(){  
  3.     alert("this.id");  
  4. },false);  
var btn=document.getElementById("myBtn");
btn.addEventListener("click",function(){
	alert("this.id");
},false);

该方法添加的事件处理程序也是在元素的作用域中运行的。

使用此方法的好处是可以添加多个事件处理程序,如下例所示:

[javascript] view plain copy
 
print?
  1. var btn=document.getElementById("myBtn");  
  2. btn.addEventListener("click",function(){  
  3.     alert("this.id");  
  4. },false);  
  5. btn.addEventListener("click",function(){  
  6.     alert("Hello World!");  
  7. },false);  
var btn=document.getElementById("myBtn");
btn.addEventListener("click",function(){
	alert("this.id");
},false);
btn.addEventListener("click",function(){
	alert("Hello World!");
},false);

这两种事件处理程序会按照添加它们的顺序触发。
b)removeEventListener()

通过addEventListener()添加的事件处理程序只能通过removeEventListener()来删除,而且需要传入的参数与添加事件处理程序的参数相同

  1. var btn=document.getElementById("myBtn");  
  2. btn.addEventListener("click",function(){  
  3.     alert("this.id");  
  4. },false);  
  5. //省略其他的代码  
  6. btn.removeEventListener("click",function(){  //没有用!传入的是完全不同的函数  
  7.     alert("this.id");  
  8. },false);  
var btn=document.getElementById("myBtn");
btn.addEventListener("click",function(){
	alert("this.id");
},false);
//省略其他的代码
btn.removeEventListener("click",function(){  //没有用!传入的是完全不同的函数
	alert("this.id");
},false);

可使用下例方法:

[javascript] view plain copy
 
print?
  1. var btn=document.getElementById("myBtn");  
  2. var handler=function(){  
  3.     alert("this.id");  
  4. };  
  5. btn.addEventListener("click",handler,false);  
  6.   
  7. //省略其他的代码  
  8. btn.removeEventListener("click",handler,false);  
var btn=document.getElementById("myBtn");
var handler=function(){
	alert("this.id");
};
btn.addEventListener("click",handler,false);

//省略其他的代码
btn.removeEventListener("click",handler,false);

大多数都是将事件处理程序添加到事件流中的冒泡阶段,可以更好的兼容更多的浏览器。

4)IE事件处理程序

IE中使用与DOM类似的两种方法:attachEvent()和detachEvent()。只接受相同的两个参数:事件处理程序名称和事件处理程序函数。IE只支持冒泡。

a)attachEvent()

[javascript] view plain copy
 
print?
  1. var btn=document.getElementById("myBtn");  
  2. btn.attachEvent("onclick",function(){  //参数为onclick,与DOM中addEventListener中的参数不同  
  3.         alert("Clicked");  
  4. });  
var btn=document.getElementById("myBtn");
btn.attachEvent("onclick",function(){  //参数为onclick,与DOM中addEventListener中的参数不同
        alert("Clicked");
});

此方法中的事件处理程序会在全局作用域中运行,因此this等于window,如下例所示:

[javascript] view plain copy
 
print?
  1. var btn=document.getElementById("myBtn");  
  2. btn.attachEvent("onclick",function(){  
  3.     alert(this==window); //true  
  4. });  
var btn=document.getElementById("myBtn");
btn.attachEvent("onclick",function(){
	alert(this==window); //true
});

attachEvent()也可以为一个元素添加多个事件处理程序。但添加的事件处理程序不是以添加的顺序执行,而是以相反的顺序被触发。

b)detachEvent()

两种方法的参数必须是相同的,意味着添加的匿名函数将不能被移除。可使用下述方法,将保存在变量handler中的函数作为事件处理程序:

[javascript] view plain copy
 
print?
  1. var btn=document.getElementById("myBtn");  
  2. var handler=function(){  
  3.     alert("Clicked");  
  4. };  
  5. btn.attachEvent("onclick",handler);  
  6. btn.detachEvent("onclick",handler);  
var btn=document.getElementById("myBtn");
var handler=function(){
	alert("Clicked");
};
btn.attachEvent("onclick",handler);
btn.detachEvent("onclick",handler);

5)跨浏览器的事件处理程序

创建方法addHandler()方法和removeHandler()方法,方法属于一个EventUtil对象,用于添加和移除事件处理成程序。如下所示:

[javascript] view plain copy
 
print?
  1. //跨浏览器的事件处理程序  
  2. var EventUtil={  
  3.     addHandler:function(element,type,handler){  
  4.         if(element.addEventListener){  //检测DOM2级方法  
  5.             element.addEventListener(type,handler,false);  
  6.         } else if(element.attachEvent){  //检测IE方法  
  7.             element.attachEvent("on"+type,handler);  
  8.         } else{  
  9.             element["on"+type]=handler;   //使用DOM0方法  
  10.         }  
  11.     },  
  12.     removeHandler:function(element,type,handler){  
  13.         if(element.removeEventListener){  //检测DOM2级方法  
  14.             element.removeEventListener(type,handler,false);  
  15.         } else if(element.detachEvent){  //检测IE方法  
  16.             element.detachEvent("on"+type,handler);  
  17.         } else{  
  18.             element["on"+type]=null;   //使用DOM0方法  
  19.         }  
  20.     }  
  21. };  
//跨浏览器的事件处理程序
var EventUtil={
	addHandler:function(element,type,handler){
		if(element.addEventListener){  //检测DOM2级方法
			element.addEventListener(type,handler,false);
		} else if(element.attachEvent){  //检测IE方法
			element.attachEvent("on"+type,handler);
		} else{
			element["on"+type]=handler;   //使用DOM0方法
		}
	},
	removeHandler:function(element,type,handler){
		if(element.removeEventListener){  //检测DOM2级方法
			element.removeEventListener(type,handler,false);
		} else if(element.detachEvent){  //检测IE方法
			element.detachEvent("on"+type,handler);
		} else{
			element["on"+type]=null;   //使用DOM0方法
		}
	}
};

可以像下面这样使用EventUtil对象:

[javascript] view plain copy
 
print?
  1. var btn=document.getElementById("myBtn");  
  2. var handler=function(){  
  3.     alert("Clicked");  
  4. };  
  5. EventUtil.addHandler(btn,"click",handler);  
  6. //省略其他代码  
  7. EventUtil.removeHandler(btn,"click",handler);  
var btn=document.getElementById("myBtn");
var handler=function(){
	alert("Clicked");
};
EventUtil.addHandler(btn,"click",handler);
//省略其他代码
EventUtil.removeHandler(btn,"click",handler);

该两种方法仅用来添加和移除事件处理程序,并没有考虑所有的浏览器问题,例如IE中作用域问题。

未完待续(*^__^*)

参考:《JavaScript高级程序设计(第二版)》

原文地址:https://www.cnblogs.com/zhangxiaolei521/p/5987036.html