javascript事件(1)

事件流

所谓的事件流,就是指从页面接收事件的顺序。所谓的事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间。

事件冒泡

IE中的事件流叫做事件冒泡,即事件开始时是由最具体的元素接收,然后逐级向上传播到较为不具体的节点。

<!doctype html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>事件流</title>
</head>
<body>
	<div id='myDiv'>点击</div>
</body>
</html>
当点击上面代码的div元素时,事件的传播顺序如下图所示:

冒泡事件

在事件冒泡过程中,click事件首先是发生在div元素上的,然后才逐级向起父层传播。

事件捕获

Netscape的事件流是事件捕获。事件捕获的思想是:事件是从不太具体的节点传播到具体的节点的。

仍以上面的html页面作为例子,事件捕获中,事件的传播顺序如下图所示:

事件捕获

在事件捕获过程中,document对象最先接收到click事件,然后事件沿DOM树依次向下,直到传播到事件的实际目标为止,这里的目标即div元素。

DOM事件流

‘DOM2级事件’的事件流有三个阶段,分别为:事件捕获阶段、处于目标阶段和事件冒泡阶段。

同样以前面的html页面为例,DOM2级事件流的传播顺序如下图所示:

DOM2级事件流

注意,在捕获阶段,实际目标(在这个例子中,即div元素)是不会接收事件的。在处于目标阶段事件被接收,并且在事件处理中被看成是冒泡阶段的一部分。

事件处理程序

响应某个事件的函数,就叫做事件处理程序(或事件侦听器)。

HTML事件处理程序

HTML事件处理程序就是指与每种事件同名的HTML特性。而这里的特性值应该是能够执行的javascript代码。

如,click事件,作为事件处理程序,在html中可以这样表示:

<input type="button" value="Click Me" οnclick="alert('Clicked')" />
注意,作为特性值的javascript代码,不能使用未经转义的HTML语法字符,如和号(&)、双引号(“”)、小于号(<)、大于号(>)等。

还可以像下面这样指定html事件处理程序:

<script type="text/javascript">
       function showMessage(){
           alert('Hello world!');
       }
</script>
<input type="button" value="Click Me" οnclick="showMessage()" />

DOM0级事件处理程序

DOM0级的事件处理程序就是将一个函数赋给一个事件处理程序属性。在这里,事件处理程序被认为是元素的方法,通常全部小写。并且,此时事件处理程序是在元素的作用域中运行的,即程序中this引用当前的元素。

<input type="button" value="Click Me" id="myBtn" />
<script type="text/javascript">
       var btn=document.getElementById('myBtn');
       btn.οnclick=function(){
       	   alert(this.id); //myBtn
       };
</script>
以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。

也可以删除通过DOM0级方法指定的事件处理程序,只要将他们的值设置为null即可:

btn.οnclick=null; //删除事件处理程序
删除事件处理程序后,再单机按钮将不会有任何动作发生。

DOM2级事件处理程序

DOM2级事件定义了两个方法,用于处理指定和删除事件处理程序,它们分别为:addEventListener()和removeEventListener()。

这两个方法都接受三个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。

最后一个布尔值参数,如果是true,则表示在捕获阶段调用事件处理程序;如果是false,则表示在冒泡阶段调用事件处理程序。

<input type="button" value="Click Me" id="myBtn" />
<script type="text/javascript">
       var btn=document.getElementById('myBtn');
       btn.addEventListener('click',function(){
       	   alert(this.id);  //myBtn
       },false)
</script>
试用DOM2级方法,可以为元素添加多个事件处理程序,它们是按照添加的顺序来一次执行的:

<input type="button" value="Click Me" id="myBtn" />
<script type="text/javascript">
       var btn=document.getElementById('myBtn');
       btn.addEventListener('click',function(){
       	   alert(this.id);  //myBtn
       },false);

       btn.addEventListener('click',function(){
       	   alert('Hello world!'); //Hello world!
       },false);
</script>

上面这段代码,会依次弹窗两个弹窗,第一个显示’myBtn‘,第二个显示’Hello world!'.

通过addEventListener()添加的事件处理程序只能通过removeEventListener()来删除,并且,移除时传人的参数必须和添加处理程序时传人的参数相同,否则将无法移除。

注意:addEventListener()添加的匿名函数将无法被移除。即上面的两个事件处理程序是无法被移除的。

因此,可以在外部定义函数,然后再将其传人事件处理程序中,这样的就可以在删除事件处理程序中传人一样的函数了:

<input type="button" value="Click Me" id="myBtn" />
<script type="text/javascript">
       var btn=document.getElementById('myBtn');
       var handler=function(){
       	  alert(this.id);
       }

       btn.addEventListener('click',handler,false);  

       btn.removeEventListener('click',handler,false);

</script>
像这样一段代码,点击按钮是不会产生任何效果的。因为事件处理程序被成功移除了。

IE事件处理程序

IE也有两个方法,用于添加和删除事件处理程序,分别为:attachEvent()和detachEvent()。

这两个方法也接受两个相同的参数:事件处理程序名称和事件处理程序函数。由attachEvent()添加的事件处理程序会被添加到冒泡阶段。

注意:attachEvent()的第一个参数与addEventListener()的第一个参数是不同的,会在前面多一个'on‘:

var btn=document.getElementById('myBtn');
btn.attachEvent('onclick',function(){
    alert('Clicked!');
});
在使用attachEvent()方法的情况下,事件处理程序会在全局作用域中运行,因此this是等window,而不是元素:

<input type="button" value="Click Me" id="myBtn" />
<script type="text/javascript">
       var btn=document.getElementById('myBtn');
       btn.attachEvent('onclick',function(){
       	    alert(this===window); //true
       });

</script>
与addEventListener()一样,attachEvent()也可以为一个元素添加多个事件处理程序,但是,与addEventListener()不同的是,用attachEvent()添加的事件处理程序执行的顺序是相反的,即最后添加的会最先执行:

<input type="button" value="Click Me" id="myBtn" />
<script type="text/javascript">
       var btn=document.getElementById('myBtn');
       btn.attachEvent('onclick',function(){
       	    alert('clicked!'); 
       });
       btn.attachEvent('onclick',function(){
       	    alert('Hello!'); 
       });
</script>
上面这段代码,依次弹出的是:’Hello!‘、’clicked!‘。

使用attachEvent()添加的事件可以用detachEvent()来移除,并且传人的参数也要是相同的:

<input type="button" value="Click Me" id="myBtn" />
<script type="text/javascript">
       var btn=document.getElementById('myBtn');
       var handler=function(){
       	   alert('clicked!'); 
       };

       btn.attachEvent('onclick',handler);
       btn.detachEvent('onclick',handler); 
       
</script>
上面这段代码,点击按钮,将不会有任何反应,因为事件已被移除。

跨浏览器的事件处理程序

通过上面的介绍,可以知道,要保证处理事件的代码在大多数浏览器下一致运行,只需要关注冒泡阶段即可,因此可以视情况分别使用DOM0级方法、DOM2级方法或IE方法来添加事件:

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;
                     }
              }
};
利用上面的对象,我们一起来看一个跨浏览器添加事件处理程序的例子:
<input type="button" value="Click Me" id="myBtn" />
<script type="text/javascript">
       
       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;
       	   	   }
       	   }
       };

       var btn=document.getElementById('myBtn');

       var handler=function(){
       	   alert('Hello world!');
       }

       EventUtil.addHandler(btn,'click',handler);  //Hello world!

       EventUtil.removeHandler(btn,'click',handler);

</script>

事件对象

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

所有浏览器都支持event对象,但是支持的方式不同。

HTML事件处理程序中的事件对象

HTML事件处理程序会创建一个封装着元素属性值的函数,该函数有一个局部变量event,也就是事件对象。

通过event变量,可以直接访问事件对象,this值等于事件的目标元素。

<input type='button' value='click me' οnclick='alert(this.value)' />
这个动态创建的函数,还可以像访问局部变量一样访问document及该元素本身的成员:

<input type='button' value='click me' οnclick='alert(value)' />
如果当前元素是一个表单输入元素,则作用域中还会包含访问表单元素(父元素)的入口:

<form method="post">
       <input type="text" name="username" value="">
       <input type="button" value="Echo Username" οnclick="alert(username.value)">
</form>
这里,直接引用了username元素,返回了它的值。

在HTML中指定事件处理程序有两个缺点:

  1. 存在时差问题。用户可能会在HTML元素一出现在页面上就触发相应的事件,这是要是处理程序尚不具备执行条件,将会保存。所以,将HTML事件处理程序封装在try-catch块中,是经常的作法。
  2. 这样扩展事件处理程序的作用域在不同浏览器中会导致不同的结果。

因此,不建议使用HTML事件处理程序,而应该用javascript指定事件处理程序。

DOM中的事件对象

无论指定事件处理程序时使用什么方法(DOM0级或DOM2级),都会传人event对象。它包含与创建它的特性事件有关的属性和方法。

触发的事件类型不一样,可用的属性和方法也不一样,不过,所有事件都会有下表列出的成员:

属性/方法类型读/写说明
bubblesBoolean只读表明事件是否冒泡
cancelableBoolean只读表明是否可以取消事件的默认行为
currentTargetElement只读其事件处理程序当前正在处理事件的那个元素
defaultPreventedBoolean只读为true表示已经调用了preventDefault()
detailInteger只读与事件相关的细节信息
eventPhaseInteger只读调用事件处理程序的阶段:1表示捕获阶段,2表示“处于目标”阶段,3表示冒泡阶段
preventDefault()Function只读取消事件的默认行为。如果cancelable是true,则可以使用这个方法
stopImmediatePropagation()Function只读取消事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用
stopPropagation()Function只读取消事件进一步捕获或冒泡。如果bubbles为true,则可以使用这个方法
targetElement只读事件的目标
trustedBoolean只读为true表示事件是浏览器生成的。为false表示事件是有开发人员通过javascript创建的
typeString只读被触发的事件的类型
viewAbstractView只读与事件关联的抽象视图。等同于发生事件的window对象

在事件处理程序内部,对象this始终等于currentTarget的值,而target则只包含事件的实际目标。如果直接将事件处理程序指定给了目标元素,则this、currentTarget和target包含相同的值。

注意:只有在事件处理程序执行期间,event对象才会存在,一旦事件处理程序执行完成,event对象就会被销毁。

IE中的事件对象

与访问DOM中的event对象不同,要访问IE中的event对象有几种不通过的方法,取决于指定事件处理程序的方法。

在使用DOM0级方法添加事件处理程序时,event对象作为window对象的一个属性存在。

如果事件处理程序是使用attachEent()添加的,那么就会有一个event对象作为参数被传入事件处理程序函数中。

//DOM0级方法
<a href="#" id="myBtn">click me</a>
<script type="text/javascript">
       var btn=document.getElementById('myBtn');
       btn.οnclick=function(){
       	   var event=window.event;
       	   alert(event.type); //click
       }
</script>

//attachEent()方法
<a href="#" id="myBtn">click me</a>
<script type="text/javascript">
       var btn=document.getElementById('myBtn');
       btn.attachEvent('onclick',function(event){
            alert(event.type); //click
       });
</script>

IE的event对象同样也包含与创建他的事件相关的属性和方法,这些属性和方法也会因为事件类型的不同而不同,但所有事件对象都会包含下列属性和方法:

属性/方法类型读/写说明
cancelBubbleBoolean读/写默认值是false,但将其设置为true就可以取消事件冒泡(与DOM中的stopPropagation()方法的作用相同)
returnValueBoolean读/写默认值为true,但将其设置为false就可以取消事件的默认行为(与DOM中的preventDefault()方法的作用相同)
srcElementElement只读事件的目标(与DOM中的target属性相同)
typeString只读被触发事件的类型

跨浏览器的事件对象

虽然DOM和IE中的event对象不同,但是IE中event对象的全部信息和方法DOM对象中都有,只不过实现方式不一样,所以还是可以实现跨浏览器获得事件对象。

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;
       	   	   }
       	   },
		   //获得event对象
		   getEvent:function(event){
		      return event?event:window.event;
		   },
		   //获得事件目标
		   getTarget:function(event){
		      return event.target||event.srcElement;
		   },
		   //取消默认行为
		   preventDefault:function(event){
		      if(event.preventDefault){
			     event.preventDefault();
			  }else{
			     event.returnValue=false;
			  }
		   },
		   //阻止事件冒泡
		   stopPropagation:function(event){
		      if(evemt.stopPropagation){
			     event.stopPropagation();
			  }else{
			     event.cancelBubble=true;
			  }
		   }
		   
};
除了前面添加的添加事件以及移除事件的方法外,这里还新添加了四个方法,分别为getEvent()、getTarget()、preventDefault()和stopPropagation()。

在使用这些方法时,必须假设有一个事件对象传人到事件处理程序中,而且要把该变量传给这个方法:

btn.οnclick=function(event){
   <strong>event=EventUtil.getEvent(event);</strong>
}
获得事件目标:

btn.οnclick=function(event){
   event=EventUtil.getEvent(event);
   <strong>var target=EventUtil.getTarget(event);</strong>
}
取消默认行为:

btn.οnclick=function(event){
   event=EventUtil.getEvent(event);
   <strong>EventUtil.preventDefault(event);</strong>
}
阻止冒泡跟取消默认行为一样,直接调用EventUtil对象的stopPropagation()方法。


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值