什么是事件委托呢?
首先,委托呢,就是讓別人來做,這個事件本來是加在某些元素上的,然而你卻加到別人身上來做,完成這個事件。舉個例子,比如說送快遞,如果一個快遞員送一個公司的快遞,他可以選擇在公司聯系每個人來取這個快遞,當然另一種方法就是把快遞讓前台的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元素,則為事件委托,否則為正常的事件綁定。
最后:希望本文所述對大家的事件委托理解有所幫助!!!