js的事件委托

Posted JcScript

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js的事件委托相关的知识,希望对你有一定的参考价值。

什么是事件委托呢?

首先,委托呢,就是让别人来做,这个事件本来是加在某些元素上的,然而你却加到别人身上来做,完成这个事件。举个例子,比如说送快递,如果一个快递员送一个公司的快递,他可以选择在公司联系每个人来取这个快递,当然另一种方法就是把快递让前台的MM代收,然后公司的人只要自己来前台取就ok了,虽然结果是一样的,但是效率却变快了许多。这里面可以把员工来取快递的行为看作是事件冒泡(什么是事件冒泡上篇文章有提)。

特别注意:

事件委托是通过事件冒泡实现的,所以如果子级的元素阻止了事件冒泡,那么事件委托也将失效!

举个简单的事件委托例子:

下面代码是一个普通的事件绑定

 

<ul id="ul">
  <li>aaaaaaaa</li>
  <li>bbbbbbbb</li>
  <li>cccccccc</li>
</ul>
window.onload = function(){
  var oUl = document.getElementById("ul");
  var aLi = oUl.getElementsByTagName("li");

  for(var i=0; i<aLi.length; i++){
    aLi[i].onmouseover = function(){
      this.style.background = "red";
    }
    aLi[i].onmouseout = function(){
      this.style.background = "";
    }
  }
}

这样子我们可以通过for循环来遍历每一个li节点从而实现事件的绑定。但是有一个问题,上面代码只有三个dom界面,如果有需求需要的dom节点特别多,那么这就存在了性能的问题了。

下面我们可以用事件委托的方式来实现这样的效果:

oUl.onmouseover = function(e){
    var e = e || window.event;
    var target = e.target || e.srcElement;
    //alert(target.innerhtml);
    if(target.nodeName.toLowerCase() == "li"){
    target.style.background = "red";
    }
  }
  oUl.onmouseout = function(e){
    var e = e || window.event;
    var target = e.target || e.srcElement;
    //alert(target.innerHTML);
    if(target.nodeName.toLowerCase() == "li"){
    target.style.background = "";
    }
  }
}

我们通过event.target来实现事件委托,这里用到了事件源:event。什么是事件源呢?记住不管在那个事件中,只要你操作的那个元素就是事件源。

显而易见,这种方法就避免了for循环,从而提高了代码的性能,这也是事件委托的第一个好处:提高性能!

让我们再看一段代码:

下面的代码是如何操作后添加的dom元素

window.onload = function(){
  var oUl = document.getElementById("ul");
  var aLi = oUl.getElementsByTagName("li");
  var oBtn = document.getElementById("btn");
  var iNow = 4;
  for(var i=0; i<aLi.length; i++){
    aLi[i].onmouseover = function(){
      this.style.background = "red";
    }
    aLi[i].onmouseout = function(){
      this.style.background = "";
    }
  }
  oBtn.onclick = function(){
    iNow ++;
    var oLi = document.createElement("li");
    oLi.innerHTML = 1111 *iNow;
    oUl.appendChild(oLi);
  }
}

这段代码用到了window.onload来实现事件的绑定,不过不用这个方法,那么事件肯定是失效。因为你绑定事件时根本就不存在这个dom元素,那么事件必然事件。

而事件委托就不会有这种问题。

window.onload = function(){
  var oUl = document.getElementById("ul");
  var aLi = oUl.getElementsByTagName("li");
  var oBtn = document.getElementById("btn");
  var iNow = 4;
  oUl.onmouseover = function(e){
    var e = e || window.event;
    var target = e.target || e.srcElement;
    //alert(target.innerHTML);
    if(target.nodeName.toLowerCase() == "li"){
    target.style.background = "red";
    }
  }
  oUl.onmouseout = function(e){
    var e = e || window.event;
    var target = e.target || e.srcElement;
    //alert(target.innerHTML);
    if(target.nodeName.toLowerCase() == "li"){
    target.style.background = "";
    }
  }
  oBtn.onclick = function(){
    iNow ++;
    var oLi = document.createElement("li");
    oLi.innerHTML = 1111 *iNow;
    oUl.appendChild(oLi);
  }
}
IE:window.event.srcElement
标准下:event.target
nodeName:找到元素的标签名

其实事件委托的核心不过是通过event.target(当前事件元素).nodeName(dom元素的标签名)取到标签,然后用event.target.style.xxx(例子中给的是background)来操作dom
window.event.srcElement是为了兼容ie
下面是兼容浏览器写出的一个target事件
    var e = e || window.event;
    var target = e.target || e.srcElement;

这个如实事件委托的最核心,最有用的地方(个人认为),就是能够给后插入的dom节点绑定事件。一般我们用ajax调用接口返回的是一个大的json串,然后通过这个返回json动态插入数据(dom),这时候我们使用事件委托就不会出来事件绑定失效了。

jquery下的事件委托:

$(document).on(click,li,function(){
    alert(这是一个li!!!);
});

这就是一个事件委托。其实最开始的事件委托是封装的bind(),live()和delegate(),

首先我们先说bind()

$("ul li").bind("click", function(){
  alert(这是一个li!!!);
});

问题是,如果ul中要绑定1000个里,那么查找遍历1000个li会导致脚本运行速度很慢,而保存1000个li元素和事件处理程序也会占用大量的内存,所以这种方式我们不推荐。

下面我们来说第二种live()

$("ul li").live("click", function(){
  alert(这是一个li!!!);
});
live()事件委托可以解决上述两个问题。具体到代码上,只要用jQuery 1.3新增的.live()方法代替.bind()方法即可。
但是live也是有问题的。
1.$()函数会找到当前页面中的所有li元素并创建jQuery对象,但在确认事件目标时却不用这个li元素集合,而是使用选择符表达式与event.target或其祖先元素进行比较,因而生成这个jQuery对象会造成不必要的开销。

2.默认把事件绑定到$(document)元素,如果DOM嵌套结构很深,事件冒泡通过大量祖先元素会导致性能损失。
这些问题也是.live()方法饱受诟病的一个重要原因。
为了解决上面两个方法带来的问题,jquery在1.4.2版本引入了一个新的delegate(),代码如下:

$("ul li").delegate("click", function(){
  alert(这是一个li!!!);
});

jquery 1.7为了解决.bind()、.live()和.delegate()并存造成的不一致性问题,将会增加一对新的事件方法:.on()
所以现在我们用jquery都是用on绑定事件(也是我最开始写的事件委托的方式)。jquery规定on()中的第二个参数如果是dom元素,则为事件委托,否则为正常的事件绑定。
最后:希望本文所述对大家的事件委托理解有所帮助!!!
 
 

以上是关于js的事件委托的主要内容,如果未能解决你的问题,请参考以下文章

JS中的事件(对象,冒泡,委托,绑定)

js事件委托

(JS 事件委托)如何删除目标元素?

js事件委托

js事件代理(事件委托)最简单的理解

JS 中的事件绑定事件监听事件委托