JavaScript事件代理和委托

浏览器的事件冒泡

当事件发生后,这个事件就要开始传播。例如咱们点击一个按钮时,就会产生一个click事件,但这个按钮自己不能处理这个事件,事件必须从这个按钮传播出去,从而到达可以处理这个事件的代码中。从里到外,直至它被处理,或者它到达了对象层次的最顶层,即document对象(有些浏览器是window)javascript

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

  IE 5.5: div -> body -> documentjava

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

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

(2)捕获型事件(event capturing):事件从最不精确的对象(document 对象)开始触发,而后到最精确的对象web

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

DOM2.0模型将事件处理流程分为三个阶段:1、事件捕获阶段,2、事件目标阶段,3、事件起泡阶段。如图:函数

事件捕获:当某个元素触发某个事件(如onclick),顶层对象document就会发出一个事件流,随着DOM树的节点向目标元素节点流去,直到到达事件真正发生的目标元素。在这个过程当中,事件相应的监听函数是不会被触发的。this

事件目标:当到达目标元素以后,执行目标元素该事件相应的处理函数。若是没有绑定监听函数,那就不执行。spa

事件起泡:从目标元素开始,往顶层元素传播。途中若是有节点绑定了相应的事件处理函数,这些函数都会被一次触发。若是想阻止事件起泡,可使用e.stopPropagation()(Firefox)或者e.cancelBubble=true(IE)来组织事件的冒泡传播。

每一个 event 都有一个event.bubbles属性,能够知道它能否冒泡。

JS事件代理

对于须要给不少列表式元素添加事件时,能够直接将事件添加到它们的父节点,将事件委托给父节点来触发处理函数。利用浏览器的事件冒泡机制实现单个元素事件处理

假设有一个ul 的父节点包含一些列li的子节点,但愿实现的效果是:鼠标移到li上时弹出悬浮窗,即li须要出发处理事件,一般写法是给每一个li绑定onclick等监听事件。

//html:
<ul id="parent">
  <li id="child1">Item 1</li>
  <li id="child2">Item 2</li>
  <li id="child3">Item 3</li>
  <li id="child4">Item 4</li>
  <li id="child5">Item 5</li>
</ul>

js代码:

//js:
function addListeners(li_child){
    li_child = function clickHandler(){...};
}

window.onload = function(){
    var ul_parent = document.getElementById("parent");
    var li_childs = ulNode.getElementByTagName("li");
    for(var i=0, l = li_childs; i < l; i++){
        addListener(li_childs[i]);
    }   
}

若是这个ul中的li子元素会频繁地添加或者删除,咱们就须要在每次添加li的时候都调用这个addListener方法来为每一个li节点添加事件处理函数。这就添加的复杂度和出错的可能性。

更简单的方法是使用事件代理机制,当事件被抛到更上层的父节点的时候,咱们经过检查事件的目标对象(target)来判断并获取事件源Li。下面的代码能够完成咱们想要的效果:

// 获取父节点,并为它添加一个click事件
document.getElementById("parent").addEventListener("click",function(e) {
  // 检查事件源e.targe是否为Li
  if(e.target && e.target.nodeName.toUpperCase == "li") {
    // 真正的处理过程在这里
    ...
  }
});

为父节点添加一个click事件,当子节点被点击的时候,click事件会从子节点开始向上冒泡。父节点捕获到事件以后,经过判断e.target.nodeName来判断是否为咱们须要处理的节点。而且经过e.target拿到了被点击的Li节点。从而能够获取到相应的信息,并做处理。

jQuery中delegate函数

delegate() 方法为指定的元素(属于被选元素的子元素)添加一个或多个事件处理程序,并规定当这些事件发生时运行的函数,使用 delegate() 方法的事件处理程序适用于当前或将来的元素(好比由脚本建立的新元素)。

$("#parent").delegate("li", "click", function(){
  // "$(this)" is the node that was clicked
  ...
});

jQuery的delegate的方法须要三个参数,一个选择器,一个时间名称,和事件处理函数。

优势

经过上面的介绍,你们应该可以体会到使用事件委托对于web应用程序带来的几个优势:

1.管理的函数变少了。不须要为每一个元素都添加监听函数。对于同一个父节点下面相似的子元素,能够经过委托给父元素的监听函数来处理事件。

2.能够方便地动态添加和修改元素,不须要由于元素的改动而修改事件绑定。

3.JavaScript和DOM节点之间的关联变少了,这样也就减小了因循环引用而带来的内存泄漏发生的几率。

jquery中对冒泡和默认行为的阻止方法

网页中的某些元素是有本身的默认行为的,好比果超连接单击后须要跳转,提交按钮点击后须要提交表单,有时须要阻止这些行为,也就是默认行为,jQuery对这个问题进行了必要的扩展和封装

 $("element").bind("click",function(event){  });   

 //event为事件对象event.stopPropagation();   //中止事件冒泡  

jquery中可用用preventDefault()的方法来阻止元素的默认行为

$('#submit').bind('click', function(event) {

    var username = $('#username').val();

    if (username == "") {

        alert('用户名不能为空!');

        event.preventDefault(); //阻止默认行为  

    }

})

jquery中对冒泡和默认行为的阻止方法能够改写,改写后可以达到一样的效果

event.preventDefault();  改写为:  return false;
event.stopPropagation();  改写为:  return false;
相关文章
相关标签/搜索