JavaScript對(duì)這種問(wèn)題的處理方式可以稱(chēng)之為事件流即事件的傳播機(jī)制。對(duì)于事件流IE跟FF有不同的解釋。IE下的解決方案稱(chēng)之為:冒泡型事件,而FF下稱(chēng)之為:捕獲型事件。顧名思義冒泡型事件是從低而上的觸發(fā)機(jī)制,而捕獲型事件則是從上到下的觸發(fā)機(jī)制。《JavaScript高級(jí)程序設(shè)計(jì)》一書(shū)提到:
DOM事件流同時(shí)支持兩種事件觸發(fā)機(jī)制,但是捕獲型事件先發(fā)生。注意因?yàn)槭录哪繕?biāo)(也就是DOM樹(shù)最深的節(jié)點(diǎn))是最精確的元素,實(shí)際上它會(huì)連續(xù)接收兩次事件,一次是在捕獲過(guò)程中,一次是在冒泡過(guò)程中。
事情到底是不是這樣呢?觀察下面的程序:<html onclick=" clickHandle('html'); ">
<head>
<title>JAVASCRIPT事件流</title>
<meta http-equiv="content-type" content="text/html; charset=GBK">
<script type="text/javascript">
function clickHandle(ele){
alert(ele);
}
</script>
</head>
<body onclick=" clickHandle('body'); ">
<div style="bgcolor:red" onclick=" clickHandle('div'); ">click me!</div>
</body>
</html>
IE:點(diǎn)擊 click me 運(yùn)行順序?yàn)椋篋IV-->BODY-->HTML 點(diǎn)擊頁(yè)面其他部分:BODY-->HTML<head>
<title>JAVASCRIPT事件流</title>
<meta http-equiv="content-type" content="text/html; charset=GBK">
<script type="text/javascript">
function clickHandle(ele){
alert(ele);
}
</script>
</head>
<body onclick=" clickHandle('body'); ">
<div style="bgcolor:red" onclick=" clickHandle('div'); ">click me!</div>
</body>
</html>
FF: 點(diǎn)擊 click me 運(yùn)行順序?yàn)椋篋IV-->HTML-->BODY 點(diǎn)擊頁(yè)面其他部分:HTML-->BODY
呵呵,好像跟書(shū)上說(shuō)的不太一樣哦!程序的運(yùn)行結(jié)果告訴我們:不管是在IE下還是在FireFox下,事件總是由最精確的元素(也就是DOM樹(shù)中最深的節(jié)點(diǎn))首先觸發(fā),然后才開(kāi)始IE下的冒泡和FireFox下的捕獲。
JavaScript為我們提供了三種事件處理函數(shù)的分配方式,第一種就像上面的程序一樣,是在HTML代碼中分配事件處理函數(shù)。
第二種方法是在JavaScript中分配事件處理函數(shù),這種方法首先必須得獲得要分配事件處理函數(shù)的元素的引用,參考以下程序:
1 window.onload = function(){
2 var oDiv = document.getElementById("contentDiv");
3 oDiv.onclick = function(){
4 alert(oDiv.innerHTML);
5 }
6 }
就像上面提到的,該方法在分配事件處理函數(shù)時(shí)必須保證已經(jīng)獲得對(duì)該元素的引用,所以這個(gè)程序才把oDiv的onclick事件放在了onload事件的內(nèi)部,否則會(huì)報(bào)oDiv未被定義。還有一個(gè)需要注意的地方是使用這種事件處理函數(shù)的分配方式時(shí)只能為某個(gè)特定的事件分配一個(gè)函數(shù)且事件函數(shù)的簽名必須小寫(xiě),否則前面分配的函數(shù)會(huì)被后面的函數(shù)所覆蓋,如果想為同一個(gè)事件分配兩個(gè)以上的處理函數(shù),需要采用第三種事件處理函數(shù)分配方式。2 var oDiv = document.getElementById("contentDiv");
3 oDiv.onclick = function(){
4 alert(oDiv.innerHTML);
5 }
6 }
在IE中我們使用obj.attachEvent()方法為某個(gè)元素分配函數(shù),使用obj.detachEvent()方法為某個(gè)元素分離事件處理函數(shù),而在DOM(以FireFox為例)中我們使用addEventListener()方法分配函數(shù),使用removeEventListener()方法分離函數(shù)。
參考一下代碼:
1 window.onload = function(){
2 var oDiv = document.getElementById("contentDiv");
3 var func1 = function(){
4 alert(oDiv.innerHTML);
5 }
6 var func2 = function(){
7 alert("also " + oDiv.innerHTML);
8 }
9 //IE
10 if(oDiv.attachEvent){
11 oDiv.attachEvent("onclick",func1);
12 oDiv.attachEvent("onclick",func2);
13 //oDiv.detachEvent("onclick",func1);
14 } else if(oDiv.addEventListener){
15 //FireFox
16 oDiv.addEventListener("click",func1,true);
17 oDiv.addEventListener("click",func2,true);
18 //oDiv.removeEventListener("click",func1,true);
19 }
20
21 }
我們來(lái)說(shuō)明一下IE下與FireFox下這種事件處理函數(shù)的不同點(diǎn):2 var oDiv = document.getElementById("contentDiv");
3 var func1 = function(){
4 alert(oDiv.innerHTML);
5 }
6 var func2 = function(){
7 alert("also " + oDiv.innerHTML);
8 }
9 //IE
10 if(oDiv.attachEvent){
11 oDiv.attachEvent("onclick",func1);
12 oDiv.attachEvent("onclick",func2);
13 //oDiv.detachEvent("onclick",func1);
14 } else if(oDiv.addEventListener){
15 //FireFox
16 oDiv.addEventListener("click",func1,true);
17 oDiv.addEventListener("click",func2,true);
18 //oDiv.removeEventListener("click",func1,true);
19 }
20
21 }
1、在函數(shù)的第一個(gè)參數(shù)中,IE下必須有"on"做為前綴,而FF下不用,兩種情況下處理函數(shù)簽名必須小寫(xiě)。
2、FireFox下的addEventListener()函數(shù)的第三個(gè)參數(shù)表示的是:true表示在捕獲階段增加事件處理函數(shù),false表示在冒泡階段增加事件處理函數(shù),但是由于FireFox不支持冒泡事件流,所以這里我們?cè)O(shè)成True或者Flase好像沒(méi)什么區(qū)別。但是要注意的一點(diǎn)就是,如果在 addEventListener()中第三個(gè)參數(shù)設(shè)為true,那么在removeEventListener()方法中的第三個(gè)參數(shù)一定也要設(shè)為相同的值,否則方法失效。
3、在運(yùn)行時(shí)階段,IE首先執(zhí)行的是最后邊一個(gè)被增加的事件處理函數(shù)然后才是倒數(shù)第二個(gè)以此類(lèi)推,但是在FireFox下與IE相反,他會(huì)按照事件處理函數(shù)的添加順序執(zhí)行。