1. 程式人生 > >關於JavaScript中的事件代理

關於JavaScript中的事件代理

今天面試某家公司Web前端開發崗位,前面的問題回答的都還算湊活,並且又問了一下昨天面試時做的一道陣列去重問題的解題思路(關於陣列去重問題,可以觀賞我前幾天寫的:http://www.cnblogs.com/craftsman-gao/p/4766223.html。幸好前幾天專門看過這個問題,答題時才能輕鬆應對啊),因為這些以前都有過研究,所以回答起來並沒有太大困難。然而,最後面試官又出了一道程式碼題讓我漲姿勢了。題目本身很簡單:一個ul中有一千個li,如何給這一千個li繫結一個滑鼠點選事件,當滑鼠點選時alert出這個li的內容和li的位置座標xy,

<ul id="ulItem">
<li id="li1">1</li> <li id="li2">2</li> <li id="li3">3</li> ... <li id="li1000">1000</li> </ul>

需要考慮到瀏覽器相容性、事件冒泡、效率等問題。看到問題後我就直接在紙上寫下了如下答案:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var ulItem = document.getElementById("ulItem"
); var lis = document.getElementsByTagName("li"); for(var i=0; i<lis.length; i++){ lis[i].onclick = function(){ alert("內容:"+this.innerHTML); alert("位置:"+getElementPosition(this).x+","+getElementPosition(this).y; } } function getElementPosition(e){ var x=0,y=0; while(e != null){ x += e.offsetLeft;
y += e.offsetTop; e = e.offsetParent; }<br>  return {x:x, y:y}; }

寫完了又看了一遍感覺沒必要考慮相容性、事件冒泡啊。效率的話,想了想,也想不出怎麼提升了,就這樣給面試官看了。面試官人也挺好的,他看了之後說:你並沒有考慮到我說的重點啊,你這樣1000次迴圈新增點選事件效率是很低的。然後就跟我講了利用事件冒泡的特性,來提高效率,即事件代理(ps:以前做專案有遇到過要阻止事件冒泡的時候,但利用事件冒泡特性提高效率卻還完全不知道)。聽了面試官講的漲了姿勢,回來後自己也上網查了一下,現在自己再總結下當做記錄自己學習的過程吧:

事件代理(Event Delegation),又稱之為事件委託。是 JavaScript 中常用繫結事件的常用技巧。顧名思義,“事件代理”即是把原本需要繫結的事件委託給父元素,讓父元素擔當事件監聽的職務。

為什麼要這麼做?眾所周知,DOM操作是十分消耗效能的,所以重複的事件繫結簡直是效能殺手。而事件代理的核心思想,就是通過儘量少的繫結,去監聽儘量多的事件。程式猿的事,沒程式碼說個J8,下面貼出程式碼:

複製程式碼
var ulItem = document.getElementById("ulItem");
ulItem.onclick = function(e){
    e = e || window.event;//這一行和下一行是為了相容IE8以及之前版本
    var target = e.target || e.srcElement;
    if(target.tagName.toLowerCase() === "li"){
        alert(target.innerHTML);
        alert("位置為:"+getElementPosition(target).x+","+getElementPosition(target).y);
    }
}
function getElementPosition(e){
    var x=0,y=0;
    while(e != null){
        x += e.offsetLeft;
        y += e.offsetTop;
        e = e.offsetParent;
    }
  return {x:x, y:y};
}
複製程式碼

嗯,現在程式碼去掉了for迴圈,提高了效率,也有了相容性方面的處理,感覺這個答案應該可以了吧。上面說的也就是為了一道筆試題,下面就再本著學術研究的思想說說事件代理:

  在傳統的事件處理中,你按照需要為每一個元素新增或者是刪除事件處理器。然而,事件處理器將有可能導致記憶體洩露或者是效能下降——你用得越多這種風險就越大。JavaScript事件代理則是一種簡單的技巧,通過它你可以把事件處理器新增到一個父級元素上,這樣就避免了把事件處理器新增到多個子級元素上。事件代理用到了兩個在JavaSciprt事件中常被忽略的特性:事件冒泡以及目標元素。當一個元素上的事件被觸發的時候,比如說滑鼠點選了一個按鈕,同樣的事件將會在那個元素的所有祖先元素中被觸發。這一過程被稱為事件冒泡;這個事件從原始元素開始一直冒泡到DOM樹的最上層。任何一個事件的目標元素都是最開始的那個元素,在我們的這個例子中也就是按鈕,並且它在我們的事件物件中以屬性的形式出現。使用事件代理,我們可以把事件處理器新增到一個元素上,等待一個事件從它的子級元素裡冒泡上來,並且可以得知這個事件是從哪個元素開始的。