西西軟件園多重安全檢測(cè)下載網(wǎng)站、值得信賴(lài)的軟件下載站!
軟件
軟件
文章
搜索

首頁(yè)編程開(kāi)發(fā)javascript|JQuery → JavaScript Event學(xué)習(xí)第八章:事件的順序

JavaScript Event學(xué)習(xí)第八章:事件的順序

相關(guān)軟件相關(guān)文章發(fā)表評(píng)論 來(lái)源:本站原創(chuàng)時(shí)間:2010/2/19 11:17:33字體大。A-A+

作者:不詳點(diǎn)擊:177次評(píng)論:0次標(biāo)簽: Event

  • 類(lèi)型:加殼脫殼大。126KB語(yǔ)言:中文 評(píng)分:3.5
  • 標(biāo)簽:
立即下載

在第一章中我提到一個(gè)初次看起來(lái)可能不是那么好理解的是一個(gè)問(wèn)題:“如果一個(gè)元素和他的父元素對(duì)于同樣的事件都有事件處理程序,那么哪個(gè)會(huì)首先執(zhí)行呢?”毫無(wú)疑問(wèn),看是什么瀏覽器。

基本問(wèn)題很簡(jiǎn)單。假設(shè)你的一個(gè)元素包含在另外一個(gè)元素中。

1 -----------------------------------<BR>| element1                        |<BR>|   -------------------------     |<BR>|   |element2                    |     |<BR>|   -------------------------     |<BR>|                                     |<BR>-----------------------------------<BR>

 這兩個(gè)元素都有onclick事件處理程序。如果用戶(hù)在element2上面單擊那么在元素2和元素1上都觸發(fā)了單擊事件。但是哪個(gè)事件先發(fā)生呢?哪個(gè)事件處理程序會(huì)先執(zhí)行呢?換句話(huà)說(shuō),事件順序(event order)是什么呢?

 兩種模式
毫無(wú)疑問(wèn)的,Netscape和微軟在過(guò)去那段很糟糕的日子里都做出了自己的決定。
Netscape說(shuō)element1先發(fā)生的。這叫事件捕獲(event capturing)。
微軟覺(jué)得element2先發(fā)生的。這叫事件冒泡(event bubbling)。
這兩種事件順序剛好相反。IE只支持事件冒泡。Mozilla,Opera 7和Konqueror兩種都支持。早一些的Opear和iCab瀏覽器兩個(gè)都不支持。

 事件捕獲
當(dāng)你使用事件捕獲的時(shí)候

1 | |<BR>---------------| |-----------------<BR>| element1      | |                |<BR>|   --------- --| |-----------     |<BR>|   |element2   \ /              |     |<BR>|   -------------------------     |<BR>|        Event CAPTURING         |<BR>-----------------------------------<BR>


element1的事件處理程序會(huì)先執(zhí)行,element2后執(zhí)行。

  事件冒泡
但你使用事件冒泡的時(shí)候

1 / \<BR>---------------| |-----------------<BR>| element1      | |                |<BR>|   ---------- -| |-----------     |<BR>|   |element2  | |               |     |<BR>|   -------------------------     |<BR>|        Event BUBBLING           |<BR>-----------------------------------<BR>


element2的事件處理程序會(huì)先執(zhí)行,element1的事件處理程序后執(zhí)行。

W3C模式
W3C決定在這場(chǎng)戰(zhàn)爭(zhēng)中保持重力。在W3C事件模型中任何事件發(fā)生都是首先被捕獲直到到達(dá)目標(biāo)元素,然后再冒泡。

1 | |  / \<BR>-----------------| |--| |-----------------<BR>| element1         | |  | |                     |<BR>|   ----------- --| |--| |-----------     |<BR>|   |element2     \ /  | |               |     |<BR>|   --------------------------------     |<BR>|        W3C event model                 |<BR>------------------------------------------<BR>

 

作為設(shè)計(jì)師的你,可以隨意選擇把事件處理程序注冊(cè)在捕獲還是冒泡階段。通過(guò)之前高級(jí)模式里面介紹的addEventListener()方法就可以完成。如果最后一個(gè)參數(shù)是true那么就設(shè)置成為事件捕獲,如果是false就設(shè)置為事件冒泡。

假設(shè)你這樣寫(xiě)
 1 element1.addEventListener('click',doSomething2,true)<BR>element2.addEventListener('click',doSomething,false)<BR>


如果用戶(hù)在element2上單擊就會(huì)發(fā)生下面的事情:
1、click事件發(fā)生在捕獲階段。這樣看來(lái),如果element2的任何一個(gè)父元素有onclick事件處理程序那么都會(huì)執(zhí)行。
2、事件在element1上發(fā)現(xiàn)了doSomething2(),那么就會(huì)執(zhí)行它。
3、事件向下傳遞直到目標(biāo)本身,再?zèng)]有其他的捕獲階段程序了。事件轉(zhuǎn)而進(jìn)入冒泡階段然后就會(huì)執(zhí)行doSomething(),也就是element2注冊(cè)在冒泡階段的事件處理程序。
4、事件再向上傳遞再檢查是否有父元素在冒泡階段設(shè)置事件處理程序。這里沒(méi)有,所以什么也不會(huì)發(fā)生。

反過(guò)來(lái):

1 element1.addEventListener('click',doSomething2,false)<BR>element2.addEventListener('click',doSomething,false)<BR>

現(xiàn)在如果用戶(hù)在element2上面點(diǎn)擊就會(huì)發(fā)生:
1、事件click發(fā)生在捕獲階段。事件會(huì)查找element2的父元素是否有在捕獲階段注冊(cè)事件處理程序,在這里沒(méi)有。
2、事件向下傳遞直到目標(biāo)本身。然后開(kāi)始冒泡階段,執(zhí)行dosomething(),這個(gè)是注冊(cè)在element2冒泡階段的事件處理程序。
3、事件繼續(xù)向上傳遞然后檢查是否有父元素在冒泡階段注冊(cè)了事件處理程序。
4、事件發(fā)現(xiàn)了element1.然后doSomething2()就被執(zhí)行了。

傳統(tǒng)模式下的兼容性
對(duì)于那些支持W3C DOM的瀏覽器來(lái)說(shuō),傳統(tǒng)的事件注冊(cè)

1 element1.onclick = doSomething2;<BR>


就被看做是注冊(cè)在冒泡階段的。

事件冒泡的使用
很少有設(shè)計(jì)師意識(shí)到事件捕獲或者冒泡。在網(wǎng)頁(yè)制作的今天,貌似沒(méi)必要讓一個(gè)冒泡事件被一系列的事件處理程序來(lái)處理。用戶(hù)也會(huì)在單擊之后發(fā)生一系列事件而感到迷惑,通常你也想讓你的事件處理程序的代碼保持一定的獨(dú)立性。當(dāng)用戶(hù)點(diǎn)擊一個(gè)元素,發(fā)生了一些事情,當(dāng)他單擊其他元素,那么其他再發(fā)生其他事情。

當(dāng)然在將來(lái)也許會(huì)改變,最好讓模式向前兼容。但是如今最實(shí)用的事件捕獲和冒泡就是默認(rèn)函數(shù)的注冊(cè)。

它總是會(huì)發(fā)生
首先你需要理解的就是事件捕獲或者冒泡總是在發(fā)生的。如果你為你的整個(gè)頁(yè)面定義了一個(gè)onclick事件:

1 document.onclick = doSomething;<BR>if (document.captureEvents) document.captureEvents(Event.CLICK);<BR>

你在任意元素上的click時(shí)間都會(huì)冒泡到頁(yè)面然后出發(fā)了這個(gè)事件處理程序。只有當(dāng)前面的事件處理程序明確的阻止冒泡,才不會(huì)傳遞到整個(gè)頁(yè)面。

使用
因?yàn)槊總(gè)事件都會(huì)在整個(gè)文檔上停止,默認(rèn)的事件處理程序就變得可能。假設(shè)你有一個(gè)這樣的頁(yè)面:

1 ------------------------------------<BR>| document                         |<BR>|   ---------------  ------------  |<BR>|   | element1     |  | element2 |  |<BR>|   ---------------  ------------  |<BR>|                                  |<BR>------------------------------------<BR><BR>element1.onclick = doSomething;<BR>element2.onclick = doSomething;<BR>document.onclick = defaultFunction;<BR>

現(xiàn)在如果用戶(hù)點(diǎn)擊了element1或者element2那么doSomething()就會(huì)執(zhí)行。在這如果你愿意也可以阻止他的傳播。如果不的話(huà),那么defaultFunction()就會(huì)執(zhí)行。用戶(hù)在其他地方的點(diǎn)擊也會(huì)讓defaultFunction()執(zhí)行。有時(shí)候這可能有用。

設(shè)置全局的事件處理程序在寫(xiě)拖動(dòng)代碼的時(shí)候就很有必要。通常一個(gè)層上的mousedow事件會(huì)選擇這個(gè)層然后對(duì)mousemove事件做出回應(yīng)。雖然mousedown通常注冊(cè)在這個(gè)層上來(lái)避免一些瀏覽器的bug,但是其他的事件處理程序都必須是全局的(document-wide)。

記住瀏覽器邏輯的第一定律:什么都會(huì)發(fā)生的,而且經(jīng)常是在你做的準(zhǔn)備最少的時(shí)候?赡馨l(fā)生的是用戶(hù)的鼠標(biāo)瘋狂的移動(dòng)然后代碼沒(méi)有跟上導(dǎo)致鼠標(biāo)已經(jīng)不再這個(gè)層上了。

 如果在某個(gè)層上注冊(cè)了onmousemove事件處理程序,如果這個(gè)層不再響應(yīng)鼠標(biāo)的移動(dòng)了,那么肯定會(huì)讓用戶(hù)感到迷惑。
如果某個(gè)曾上注冊(cè)了onmouseup事件處理程序,那么程序會(huì)在用戶(hù)松開(kāi)鼠標(biāo)的時(shí)候程序沒(méi)有捕捉到造成這個(gè)層還在隨著鼠標(biāo)移動(dòng)。
在這種情況下事件冒泡就很重要,因?yàn)槿值氖录幚沓绦驎?huì)保證執(zhí)行的。

關(guān)掉它
但是通常你想關(guān)閉所有的相關(guān)的捕獲和冒泡。另外,如果你的文檔結(jié)構(gòu)非常的復(fù)雜(比如一大堆復(fù)雜的表格之類(lèi))你也需要關(guān)閉冒泡來(lái)節(jié)省系統(tǒng)資源。要不然瀏覽器就得一個(gè)個(gè)的查看父元素是否有事件處理程序。雖然可能一個(gè)都沒(méi)有,但是查找一樣浪費(fèi)時(shí)間。

在微軟模式里你必須講事件的cancelBubble屬性設(shè)置為true。
window.event.cancelBubble = true
在W3C模式中你必須調(diào)用stopPropagation()方法。

1 e.stopPropagation()<BR>


這會(huì)阻止這個(gè)事件的冒泡階段。阻止事件的捕獲極端基本上是不可能的。我也想知道為啥。

一個(gè)完整的跨瀏覽器的代碼如下:

1 function doSomething(e)<BR>{<BR>    if (!e) var e = window.event;<BR>    e.cancelBubble = true;<BR>    if (e.stopPropagation) e.stopPropagation();<BR>}<BR>

在不支持cancelBubble的瀏覽器里面設(shè)置也不會(huì)有啥問(wèn)題。瀏覽器會(huì)創(chuàng)建一個(gè)這樣的屬性。當(dāng)然是沒(méi)啥用的,只是為了安全。

currentTarget
我們之前講過(guò),一個(gè)事件包含target或者srcElement包含一個(gè)發(fā)生事件的元素的引用。在我們的例子是element2,因?yàn)橛脩?hù)點(diǎn)擊了他。

理解在捕獲和冒泡過(guò)程中這個(gè)target是不會(huì)改變的非常重要:他一直指向element2.

但是假設(shè)我們注冊(cè)了下面的事件處理程序:

1 element1.onclick = doSomething;<BR>element2.onclick = doSomething;<BR>


如果用戶(hù)點(diǎn)擊element2那么doSomething()執(zhí)行了兩次。那么你怎樣知道那個(gè)HTML元素處理著這個(gè)事件呢?target/scrElement也不能給出答案,從事件一開(kāi)始就一直指向element2.

為了解決這個(gè)問(wèn)題W3C添加了currentTarget屬性。它包含一個(gè)正在處理的事件的HTML元素的引用:就是我們想要的那個(gè)。不幸的是微軟模式?jīng)]有類(lèi)似的屬性。

你也可以用this關(guān)鍵字。在這個(gè)例子里就是指向正在處理的事件的HTML元素,就先currentTarget。

微軟模式的問(wèn)題
但是當(dāng)你使用微軟的事件注冊(cè)模型,this關(guān)鍵字不是只想HTML元素的。然后又沒(méi)有一個(gè)像currentTarget類(lèi)似的屬性,這就意味著如果你這么做:

1 element1.attachEvent('onclick',doSomething)<BR>element2.attachEvent('onclick',doSomething)<BR>


你就不知道那個(gè)HTML元素正在處理事件。這是微軟的事件注冊(cè)模式最嚴(yán)重的問(wèn)題所以就根本不要用他,即使是那些只在IE/win下的程序。

我希望微軟能夠盡快添加一個(gè)類(lèi)似currentTarget的屬性或者遵循標(biāo)準(zhǔn)?我們?cè)O(shè)計(jì)急需啊。

    易語(yǔ)言
    (22)易語(yǔ)言
    易語(yǔ)言開(kāi)發(fā)的軟件雖然經(jīng)常會(huì)被一些安全軟件誤報(bào)為病毒,但是易語(yǔ)言確實(shí)是一門(mén)可學(xué)很好的編程語(yǔ)言,因?yàn)槭侨形娜梢暱缙脚_(tái)編程語(yǔ)言,全中文支持,無(wú)需跨越英語(yǔ)門(mén)檻。全可視化編程,支持所見(jiàn)即所得程序界面設(shè)計(jì)和程序流程編碼。因此易語(yǔ)言也可以理解為簡(jiǎn)易的語(yǔ)言,跟語(yǔ)言語(yǔ)言等以英文為基礎(chǔ)的國(guó)外語(yǔ)言開(kāi)發(fā)平臺(tái),易語(yǔ)言學(xué)習(xí)起來(lái)更簡(jiǎn)單了。西西本次提供了易語(yǔ)言.完美破解版,十天學(xué)會(huì)易語(yǔ)言圖解教程教程易語(yǔ)言零起點(diǎn)教程易語(yǔ)言個(gè)皮膚...更多>>

    相關(guān)評(píng)論

    閱讀本文后您有什么感想? 已有人給出評(píng)價(jià)!

    • 8 喜歡喜歡
    • 3 頂
    • 1 難過(guò)難過(guò)
    • 5 囧
    • 3 圍觀圍觀
    • 2 無(wú)聊無(wú)聊

    熱門(mén)評(píng)論

    最新評(píng)論

    發(fā)表評(píng)論 查看所有評(píng)論(0)

    昵稱(chēng):
    表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
    字?jǐn)?shù): 0/500 (您的評(píng)論需要經(jīng)過(guò)審核才能顯示)