HTML文档对象的事件以及addEventListener与attachEvent介绍

来源:互联网 发布:脑死亡有奇迹吗 知乎 编辑:程序博客网 时间:2024/06/07 04:58

赠人玫瑰,手留余香.人生最大的快乐不在于占有什么,而在于追求什么的过程.

转自:http://www.cnblogs.com/niuniu/archive/2010/07/16/1778938.html

           http://blog.sina.com.cn/s/blog_8e1704000101c77p.html   

                 http://www.jb51.net/article/18220.htm

                  http://www.quirksmode.org/js/events_advanced.html


1> 首先我们来了解几个概念:“事件”、“事件流”、“事件名称”、“事件处理函数/事件监听函数“

  • 事件: 事件是用户自身或浏览器进行的特定行为。如:用户点击 也就是常用的click事件
  • 事件流:多个事件  按一定顺序触发  形成了事件流
  • 事件名称:如上面所讲的click就是事件名
  • 事件处理函数/事件监听函数(Dom的叫法)就是 事件触发后的处理函数,如obj.onclick=fn;函数,fn就是事件处理函数
2>下面我们来了解一下历史,事件是dom的一部分是在版本3中已经得到完整的说明,当前浏览器除ie(它有自己的事件      模型),其他像netscape、safari、opera都基本上遵守dom的事件模型。
 
3.>冒泡事件,其基本思想是事件从特定的事件目标向非特定的事件目标顺序触发。

   在ie5.5其冒泡顺序如下图

在ie6.o以上增加了html(为了兼容,最后避免在此标签上添加事件) 如图:

而在Mozilla 1.0中的冒泡事件是:
三种其实顺序没什么不同,只是有部分标签是否支持冒泡的差异;

4>我们再看 捕获事件

ie4.0使用的是冒泡事件,而netscape navigator使用的是捕获型事件如下图所示:

    ie只支持冒泡事件,而dom是同时支持“ 冒泡事件和捕获事件的 ”,顺序是:”捕获事件”-----》》“冒泡事件” ,前     面我们已经讲了moz,opera,safari等浏览器基本上是符合dom事件模型的,所以他们也支持“ 冒泡事件和捕获事     件的 ”,如下图:

 5>下面我们了解  怎样为标签添加事件,最常用的方法是在其标签里面添加如 一下代码(这种添加,在moz中只有“捕获事件”,等价于用addEventListener(obj,type,false)添加的函数,这个后面再讲):

<!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>    <title>无标题页</title></head><body onclick="alert('body')">  <div onclick="alert('div');">    div      <input id="Button1" onclick="alert('btn');" type="button" value="button" />  </div></body></html>


点击 按钮 在ie中,依据我们对上面的了解,很容易写出答案了,没错!ie只有冒泡事件 所以 顺序为:btn>>div>>body;

而在非ie浏览器如moz中 正如我们上面所说的  内嵌式事件  等价于addEventlistener(type,fn,false) 只从冒泡事件中 监听。所以顺序也是 btn>>div>>body;


在addEventlistener(type,fn,true添加事件时) 只监听 “捕获事件”  当第三个参数为false时  只监听冒泡事件;

<!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=gb2312" />    <title>无标题页</title>    <style type="text/css">        #ll{ background:#f00; _width: expression(this.width>200?"200px":true);}    </style></head><body id="obj1"><div id="obj2"><input id="obj3" id="Text1" type="text" /></div>            <script language="javascript" type="text/javascript">          var $=function(eid){            return typeof eid=="object"?eid:document.getElementById(eid);          };          var fn={            fn1:function(){alert("body");},            fn2:function(){alert("div");},            fn3:function(){alert("test");}          };          var et={};          et.addEvent=function(obj,type,fn,flag){            if(obj.attachEvent){                obj.attachEvent("on"+type,fn);            }else if(obj.addEventListener){                flag=(typeof flag!="undefined")?flag:true;                obj.addEventListener(type,fn,flag);            }else{                obj["on"+type]=fn;            }          };                   et.addEvent($("obj1"),"click",fn.fn1,false);         et.addEvent($("obj2"),"click",fn.fn2,false);         et.addEvent($("obj3"),"click",fn.fn3,false);         //         et.addEvent($("obj3"),"click",fn.fn3);//         et.addEvent($("obj2"),"click",fn.fn2);//         et.addEvent($("obj1"),"click",fn.fn1);    </script></body></html>

点击文本域,猜一猜分别在ie和moz(火狐)中的区别,当然在ie中由于只监听冒泡事件,所以很好判断执行顺序为:input>>div>>body

而在moz中,由于div在添加事件时,第三个参数为false,说明div只监听冒泡事件,然后我们根据dom的事件 模型  不难判断,先是ojb3>>obj2>>obj1

分别弹出input>>div>>body

 

顺便唠叨一下:向同一个标签 动态的添加事件是  执行的顺序在ie和其他非ie内核的浏览器有所不同   ie是“先进先出 ” 就是最先添加的最先执行,其他非ie内核的浏览器是 “先进后出”,就是 最后添加的事件 先执行。


window.addEventListener介绍说明



原型
public override function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void


作用
  侦听事件并处理相应的函数。


参数
1、type:String
     事件的类型。
2、listener:Function 
  侦听到事件后处理事件的函数。 此函数必须接受 Event 对象作为其唯一的参数,并且不能返回任何结果,如以下示例所示: 访问修饰符 function 函数名(evt:Event):void
3、useCapture:Boolean (default = false) 
  这里牵扯到“事件流”的概念。侦听器在侦听时有三个阶段:捕获阶段、目标阶段和冒泡阶段。顺序 为:捕获阶段(根节点到子节点检查是否调用了监听函数)→目标阶段(目标本身)→冒泡阶段(目标本身到根节点)。此处的参数确定侦听器是运行于捕获阶段、 目标阶段还是冒泡阶段。 如果将 useCapture 设置为 true,则侦听器只在捕获阶段处理事件,而不在目标或冒泡阶段处理事件。 如果useCapture 为 false,则侦听器只在目标或冒泡阶段处理事件。 要在所有三个阶段都侦听事件,请调用两次 addEventListener,一次将 useCapture 设置为 true,第二次再将useCapture 设置为 false。
4、priority:int (default = 0) 
  事件侦听器的优先级。 优先级由一个带符号的 32 位整数指定。 数字越大,优先级越高。 优先级为 n 的所有侦听器会在优先级为 n -1 的侦听器之前得到处理。 如果两个或更多个侦听器共享相同的优先级,则按照它们的添加顺序进行处理。 默认优先级为 0。
5、useWeakReference:Boolean (default = false) 
  确定对侦听器的引用是强引用,还是弱引用。 强引用(默认值)可防止您的侦听器被当作垃圾回收。 弱引用则没有此作用。
注意
使用EventDispatcher对象注册事件侦听器对象,以使侦听器能够接收事件通知。 可以为特定类型的事件、阶段和优先级在显示列表的所有节点上注册事件侦听器。   
成功注册一个事件侦听器后,无法通过额外调用addEventListener()来更改其优先级。要更改侦听器的优先级,必须首先调用 removeListener()。 然后,可以使用新的优先级再次注册该侦听器。





W3C和微软都着力于发展自己的事件注册模型来取代Netscape的传统模型。虽然对于微软的模型我不是很感冒,但是w3c的还是不错的,除了这个鼠标定位 的问题。不过现在只有小部分浏览器支持。 


W3CW3C的DOM层面事件规范注意到了传统模式的问题。他对于你想在一个元素上绑定多个事件提供了一个很好的解决办法。
 
W3C事件注册模型的关键就是addEventListener()。
你给他三个参数:事件类型,要执行的函数和一个布尔值(true或者false)我一会再解释。把我们熟知doSomething()函数注册到一个元素的onclick事件上,你可以这样做: 
element.addEventListener('click',doSomething,false) 

这种模型的魅力在于我们可以想加多少监听就可以加多少。如果用我们之前的传统模式里面的例子,我们就可以写成这样:          element.addEventListener('click',startDragDrop,false) 
                    element.addEventListener('click',spyOnUser,false) 
                                                                                                     当用户点击元素的时候两个事件处理程序都会执行。
需要注意的是W3C标准不能确定哪个事件先执行。所以你也不能认为startDragDrop()就在spyOnUser()之前执行。 

移除事件处理程序也是非常的简单,用removeEventListener()就行了。
所以:  element.removeEventListener('click',spyOnUser,false) 
就会移除第二个事件处理程序但是第一个不会发生变化。非常漂亮的程序,完全解决了传统模式下的问题。 

匿名函数 
在W3C模式下你依然可以使用匿名函数: 
复制代码代码如下:

element.addEventListener('click',function () { 
this.style.backgroundColor = '#cc0000' 
},false) 

true或者false:是addEventListener的最后一个参数,意思是你想让你的函数在捕获阶段还是冒泡阶段执行。如果你不确定,那就使用false(冒泡阶段)。 

this :在JavaScript里this关键字通常指函数的所有者。如果this指向事件发生的HTML元素,那么一切都是那么的美好,你可以很简单的做很多事情。 
不幸的是,虽然this非常的强大,但是如果你不是明确的知道他怎么运作的话使用起来还是比较难的。

在w3c模型下他的运作和在传统模式下是一样的:他表示现在正在处理事件的HTML元素。 
复制代码代码如下:

element.addEventListener('click',doSomething,false); 
another_element.addEventListener('click',doSomething,false); 
function doSomething() { 
this.style.backgroundColor = '#cc0000'; 


如果你把doSomething()注册在任意一个HTML元素的click实践上,那么当用户点击的时候这个元素的背景就会变成红色。 

哪个事件处理程序被注册了呢? 
现在这个W3C事件注册模式有一个问题就是你不知道一个元素都有哪些事件处理程序被注册了。在传统模式下面你可以: 
alert(element.onclick) 
你就可以看到哪些函数注册了,undefined就是没有函数注册在这个事件上。只是在最近的DOM Level 3事件中W3C才添加了一个eventListenerList来存储已经注册了的事件处理程序。因为太新了,鲜有浏览器支持。然而,问题已经解决了。 
还好的是removeEventListener()不会因为你没有注册元素的某个事件而返回错误,所以你可以不用担心的使用removeEventLister()。 

微软 
微软也有一个事件注册模型。跟W3C的很像,但是有一个严重的缺陷。 
注册一个事件处理程序,attach到一个元素: 
element.attachEvent('onclick',doSomething) 
或者,你需要两个事件处理程序: 
element.attachEvent('onclick',startDragDrop) 
element.attachEvent('onclick',spyOnUser) 
移除一个也非常简单: 
element.detachEvent('onclick',spyOnUser) 

缺陷 
跟W3C的相比较,微软有两个严重的问题: 
、事件总是冒泡,没有被捕捉的可能。 
、事件处理程序是被引用的,而不是拷贝的,所以this关键字总是指向window然后就一点用都没有。 
这两个问题的结果就是如果一个事件冒泡了那么你是没有可能知道哪个元素在处理事件。在后面的事件顺序一章我会详细的解释。 
而且微软的标准只被IE支持,也不能用来跨浏览器。就算你只是给windows浏览器写脚本也最好别用,因为冒泡问题会让事情变得不可收拾。