JS事件代理

来源:互联网 发布:php 不用session 编辑:程序博客网 时间:2024/05/17 08:16

事件阶段
事件分为三个阶段: 事件捕获 –> 事件目标 –> 事件冒泡

事件捕获和冒泡
事件捕获
:事件发生时(onclick,onmouseover……)首先发生在document上,然后依次传递给body、……最后到达目的节点(即事件目标)。

事件冒泡:事件到达事件目标之后不会结束,会逐层向上冒泡,直至document对象,跟事件捕获相反

  • 事件捕获:当某个元素触发某个事件(如onclick),顶层对象document就会发出一个事件流,随着DOM树的节点向目标元素节点流去,直到到达事件真正发生的目标元素。在这个过程中,事件相应的监听函数是不会被触发的。
  • 事件目标:当到达目标元素之后,执行目标元素该事件相应的处理函数。如果没有绑定监听函数,那就不执行。
  • 事件起泡:从目标元素开始,往顶层元素传播。途中如果有节点绑定了相应的事件处理函数,这些函数都会被一次触发。如果想阻止事件起泡,可以使用e.stopPropagation()(Firefox)或者e.cancelBubble=true(IE)来组织事件的冒泡传播。


事件

  1. onlick -->事件冒泡,重写onlick会覆盖之前属性,没有兼容性问题

    el.onclik = null;   //解绑单击事件,将onlick属性设为null即可
  2. addEventListener(event.type, handle, boolean); IE8及以下不支持,属于DOM2级的方法,可添加多个方法不被覆盖

    //事件类型没有on,false 表示在事件第三阶段(冒泡)触发,true表示在事件第一阶段(捕获)触发。 如果handle是同一个方法,只执行一次。ele.addEventListener('click', function(){ }, false);  //解绑事件,参数和绑定一样ele.removeEventListener(event.type, handle, boolean);
  3. attachEvent(event.type, handle ); IE特有,兼容IE8及以下,可添加多个事件处理程序,只支持冒泡阶段

    //如果handle是同一个方法,绑定几次执行几次,这点和addEventListener不同,事件类型要加on,例如onclick而不是clickele.attachEvent('onclick', function(){ }); //解绑事件,参数和绑定一样ele.detachEvent("onclick", function(){ });
  4. 默认事件行为:href=""链接,submit表单提交等 
    1. return false; 阻止独享属性(通过on这种方式)绑定的事件的默认事件

      ele.onclick = function() { ……                         //你的代码 return false;              //通过返回false值阻止默认事件行为};
    2. event.preventDefault( ); 阻止通过 addEventListener( ) 添加的事件的默认事件

      element.addEventListener("click", function(e){ var event = e || window.event; …… event.preventDefault( );      //阻止默认事件},false);
    3. event.returnValue = false; 阻止通过 attachEvent( ) 添加的事件的默认事件

      element.attachEvent("onclick", function(e){   var event = e || window.event;   ……   event.returnValue = false;       //阻止默认事件});

    事件封装

    • 接下来我们把事件绑定以及事件解绑封装成为一个函数,兼容浏览器

      // 事件绑定function addEvent(element, eType, handle, bol) { if(element.addEventListener){           //如果支持addEventListener     element.addEventListener(eType, handle, bol); }else if(element.attachEvent){          //如果支持attachEvent     element.attachEvent("on"+eType, handle); }else{                                  //否则使用兼容的onclick绑定     element["on"+eType] = handle; }}
      // 事件解绑function removeEvent(element, eType, handle, bol) { if(element.addEventListener){     element.removeEventListener(eType, handle, bol); }else if(element.attachEvent){     element.detachEvent("on"+eType, handle); }else{     element["on"+eType] = null; }}

    事件冒泡、事件捕获阻止

    event.stopPropagation( );    // 阻止事件的进一步传播,包括(冒泡,捕获),无参数event.cancelBubble = true;   // true 为阻止冒泡

    事件委托(事件代理)

    • 事件委托:利用事件冒泡的特性,将里层的事件委托给外层事件,根据event对象的属性进行事件委托,改善性能。

    • 使用事件委托能够避免对特定的每个节点添加事件监听器;事件监听器是被添加到它们的父元素上。事件监听器会分析从子元素冒泡上来的事件,找到是哪个子元素的事件。

    • 使用事件代理机制,当事件被抛到更上层的父节点的时候,我们通过检查事件的目标对象(target)

    • 来判断并获取事件源。 // 获取父节点,并为它添加一个click事件

    •  document.getElementById("parent-list").addEventListener("click",function(e) 

    • { // 检查事件源e.targe是否为Li 

    • if(e.target && e.target.nodeName.toUpperCase() == "LI") { 

    • // 真正的处理过程在这里 //alert(123); 

    • console.log("List item ",e.target.id," was clicked!");  }});


    来个例子吧,如果要单独点击table里面的td,普通做法是for循环给每个td绑定事件,td少的话性能什么差别,td如果多了,就不行了,我们使用事件委托:

     <!-- HTML --><table id="out" border="1" style="cursor: pointer;">    <tr>      <td>table01</td>      <td>table02</td>      <td>table03</td>      <td>table04</td>      <td>table05</td>      <td>table06</td>      <td>table07</td>      <td>table08</td>      <td>table09</td>      <td>table10</td>    </tr></table>  // JS  var out = document.getElementById("out");  if(out.addEventListener){      out.addEventListener("click",function(e){          var e = e||window.event;          //IE没有e.target,有e.srcElement          var target = e.target||e.srcElement;          //判断事件目标是否是td,是的话target即为目标节点td          if(target.tagName.toLowerCase()=="td"){              changeStyle(target);              console.log(target.innerHTML);          }      },false);  }else{      out.attachEvent("onclick",function(e){          var e = e||window.event;          //IE没有e.target,有e.srcElement          var target = e.target||e.srcElement;          //判断事件目标是否是td,是的话target即为目标节点td          if(target.tagName.toLowerCase()=="td"){              changeStyle(target);              console.log(target.innerHTML);          }      });  };};

    1)冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发。

      IE 5.5: div -> body -> document

      IE 6.0: div -> body -> html -> document

      Mozilla 1.0: div -> body -> html -> document -> window

    (2)捕获型事件(event capturing):事件从最不精确的对象(document 对象)开始触发,然后到最精确(也可以在窗口级别捕获事件,不过必须由开发人员特别指定)。

    (3)DOM事件流:同时支持两种事件模型:捕获型事件和冒泡型事件,但是,捕获型事件先发生。两种事件流会触及DOM中的所有对象,从document对象开始,也在document对象结束。

      DOM事件模型最独特的性质是,文本节点也触发事件(在IE中不会)。

    支持W3C标准的浏览器在添加事件时用addEventListener(event,fn,useCapture)方法,基中第3个参数useCapture是一个Boolean值,用来设置事件是在事件捕获时执行,还是事件冒泡时执行。而不兼容W3C的浏览器(IE)用attachEvent()方法,此方法没有相关设置,不过IE的事件模型默认是在事件冒泡时执行的,也就是在useCapture等于false的时候执行,所以把在处理事件时把useCapture设置为false是比较安全,也实现兼容浏览器的效果。

事件捕获阶段:事件从最上一级标签开始往下查找,直到捕获到事件目标(target)。
事件冒泡阶段:事件从事件目标(target)开始,往上冒泡直到页面的最上一级标签。

假设一个元素div,它有一个下级元素p。
<div>
  <p>元素</p>
</div>
这两个元素都绑定了click事件,如果用户点击了p,它在div和p上都触发了click事件,那这两个事件处理程序哪个先执行呢?事件顺序是什么?
 
两种模型
以前,Netscape和Microsoft是不同的实现方式。

Netscape中,div先触发,这就叫做事件捕获。

Microsoft中,p先触发,这就叫做事件冒泡。

两种事件处理顺序刚好相反。IE只支持事件冒泡,Mozilla, Opera 7 和 Konqueror两种都支持,旧版本的Opera's 和 iCab两种都不支持 。

事件捕获
当你使用事件捕获时,父级元素先触发,子级元素后触发,即div先触发,p后触发。

事件冒泡
当你使用事件冒泡时,子级元素先触发,父级元素后触发,即p先触发,div后触发。

W3C模型
W3C模型是将两者进行中和,在W3C模型中,任何事件发生时,先从顶层开始进行事件捕获,直到事件触发到达了事件源元素。然后,再从事件源往上进行事件冒泡,直到到达document。

程序员可以自己选择绑定事件时采用事件捕获还是事件冒泡,方法就是绑定事件时通过addEventListener函数,它有三个参数,第三个参数若是true,则表示采用事件捕获,若是false,则表示采用事件冒泡。

ele.addEventListener('click',doSomething2,true)

true=捕获

false=冒泡

传统绑定事件方式
在一个支持W3C DOM的浏览器中,像这样一般的绑定事件方式,是采用的事件冒泡方式。

ele.onclick = doSomething2

IE浏览器
如上面所说,IE只支持事件冒泡,不支持事件捕获,它也不支持addEventListener函数,不会用第三个参数来表示是冒泡还是捕获,它提供了另一个函数attachEvent。

ele.attachEvent("onclick", doSomething2);

附:事件冒泡(的过程):事件从发生的目标(event.srcElement||event.target)开始,沿着文档逐层向上冒泡,到document为止。

事件的传播是可以阻止的:
• 在W3c中,使用stopPropagation()方法
• 在IE下设置cancelBubble = true;
在捕获的过程中stopPropagation();后,后面的冒泡过程也不会发生了~
3.阻止事件的默认行为,例如click <a>后的跳转~
• 在W3c中,使用preventDefault()方法;
• 在IE下设置window.event.returnValue = false;
4.哇,终于写完了,一边测试一边写的额,不是所有的事件都能冒泡,例如:blur、focus、load、unload,(这个是从别人的文章里摘过来的,我没测试)。


0 0
原创粉丝点击