JavaSciprt事件中有兩個很重要的特性:事件冒泡以及目標元素。
事件冒泡: 當一個元素上的事件被觸發的時候,比如說滑鼠點選了一個按鈕,同樣的事件將會在那個元素的所有祖先元素中被觸發。這 一過程被稱為事件冒泡;這個事件從原始元素開始一直冒泡到DOM樹的最上層。
目標元素: 任何一個事件的目標元素都是最開始的那個元素,在我們的這個例子中也就是按鈕,並且它在我們的元素物件中以屬性的形 式出現。使用事件代理的話我們可以把事件處理器新增到一個元素上,等待一個事件從它的子級元素裡冒泡上來,並且可以很方便地得知這個事件是從哪個元素開始 的。
事件的冒泡和捕獲
捕獲是從上級元素到下級元素,冒泡是從下級元素到上級元素.
在IE中,每個元素和window物件都有兩個方法:attachEvent()和detachEvent()。attachEvent()用來給 一個事件附加事件處理函式。而detachEvent()用來將事件處理函式分離出來。例如:
JS程式碼
var fnClick = function() { alert(“Clicked!”); } var oDiv = document.getElementById(“div1”); oDiv.attachEvent(“onclick”, fnClick); oDiv.detachEvent(“onclick”, fnClick);
事件的冒泡有什麼好處呢?
想象一下現在我們有一個10列、100行的HTML表格,你希望在使用者點選 表格中的某一單元格的時候做點什麼。比如說我有一次就需要讓表格中的每一個單元格在被點選的時候變成可編輯狀態。如果把事件處理器加到這1000個單元格 會產生一個很大的效能問題,並且有可能導致記憶體洩露甚至是瀏覽器的崩潰。相反地,使用事件代理的話,你只需要把一個事件處理器新增到table元素上就可 以了,這個函式可以把點選事件給截下來,並且判斷出是哪個單元格被點選了。
程式碼很簡單,我們所要關心的只是如何檢測目標元素而已。比方說我們有一個 table元素,ID是“report”,我們為這個表格新增一個事件處理器以呼叫editCell函式。editCell函式需要判斷出傳到table 來的事件的目標元素。考慮到我們要寫的幾個函式中都有可能用到這一功能,所以我們把它單獨放到一個名為getEventTarget的函式中:
JS程式碼
function getEventTarget(e) {
e = e || window.event;
return e.target || e.srcElement;
}
e這個變量表示的是一個事件物件,我們只需要寫一點點跨瀏覽器的程式碼來返回 目標元素,在IE裡目標元素放在srcElemtn屬性或event.toElement屬性中,而在其它瀏覽器裡則是target或event.relatedTarget屬性。
接下來就是editCell函數了,這個函式呼叫到了 getEventTarget函式。一旦我們得到了目標元素之後,剩下的事情就是看看它是否是我們所需要的那個元素了。
JS程式碼
function editCell(e) {
var target = getEventTarget(e);
if(target.tagName.toLowerCase() === ‘td’) {
// DO SOMETHING WITH THE CELL
}
}
在editCell函式中,我們通過檢查目標元素標籤名稱的方法來確定它是 否是一個表格的單元格。這種檢查也許過於簡單了點;如果它是這個目標元素單元格里的另一個元素呢?我們需要為程式碼做一點小小的修改以便於其找出父級的td 元素。如果說有些單元格不需要被編輯怎麼辦呢?此種情況下我們可以為那些不可編輯的單元格新增一個指定的樣式名稱,然後在把單元格變成可編輯狀態之前先檢 查它是否不包含那個樣式名稱。選擇總是多樣化的,你只需找到適合你應用程式的那一種。
事件冒泡的優點和缺點:
1.那些需要建立的以及駐留在記憶體中的事件處理器少了。
這是很重要的一點,這樣我們就提高了效能,並降低了崩潰的風險。
2.在DOM更新後無須重新繫結事件處理器了。
如果你的頁面是動態生成的,比如說通過Ajax,你不再需要在元素被載入或 者解除安裝的時候來新增或者刪除事件處理器了。
潛在的問題也許並不那麼明顯,但是一旦你注意到這些問題,你就可 以輕鬆地避免它們:你的事件管理程式碼有成為效能瓶頸的風險,所以盡 量使它能夠短小精悍。
不是所有的事件都能冒泡
blur、focus、load和unload不能像其它事件一樣冒泡。事 實上blur和focus可以用事件捕獲而非事件冒泡的方法獲得(在IE之外的其它瀏覽器中)。
需要注意的是:
如果你的程式碼處理mousemove事件的話你遇上效能瓶頸的風險可就大了,因為mousemove事件觸發非常頻繁。而mouseout則因為其 怪異的表現而變得很難用事件代理來管理。
消除冒泡事件的方法:
阻止JavaScript事件冒泡傳遞(cancelBubble 、stopPropagation)
下面的一段程式碼即可以很好的解釋是麼是冒泡效果,什麼叫消除冒泡效果
HTML程式碼
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<title> 阻止JavaScript事件冒泡傳遞(cancelBubble 、stopPropagation)</title>
<meta name=”keywords” content=”JavaScript,事件冒泡,cancelBubble,stopPropagation” />
<script type=”text/javascript”>
function doSomething (obj,evt) {
alert(obj.id);
var e=(evt)?evt:window.event; //判斷瀏覽器的型別,在基於ie核心的瀏覽器中的使用cancelBubble
if (window.event) {
e.cancelBubble=true;
} else {
//e.preventDefault(); //在基於firefox核心的瀏覽器中支援做法stopPropagation
e.stopPropagation();
}
}
</script>
</head>
<body>
<div id=”parent1″ onclick=”alert(this.id)” style=”width:250px;background-color:yellow”>
<p>This is parent1 div.</p>
<div id=”child1″ onclick=”alert(this.id)” style=”width:200px;background-color:orange”>
<p>This is child1.</p>
</div>
<p>This is parent1 div.</p>
</div>
<br />
<div id=”parent2″ onclick=”alert(this.id)” style=”width:250px;background-color:cyan;”>
<p>This is parent2 div.</p>
<div id=”child2″ onclick=”doSomething(this,event);” style=”width:200px;background-color:lightblue;”>
<p>This is child2. Will bubble.</p>
</div>
<p>This is parent2 div.</p>
</div>
</body>
</html>
但是單擊chile2只會彈出child2卻不會彈出 parent2,這便是應用了阻止冒泡事件的特效的效果。