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元素,则为事件委托,否则为正常的事件绑定。
最后:希望本文所述对大家的事件委托理解有所帮助!!!