先看看都有哪些滑鼠事件:mousedown,mouseup_and_click,dblclick,mousemove和mouseover mouseout。然後還會解釋一下relatedTarget,fromElement和toElement這些事件屬性。最後是微軟的mouseenter和mouseleave事件。
瀏覽器的相容性問題,可以在瀏覽器安全色性列表查看。
例子
這裡有一個例子。可以協助理解下面的內容。
mousedown,mouseup,click和dblclick在這個連結上註冊。可以再下面的文字框裡面查看。或者在對話方塊裡面。(請在原文裡嘗試:http://www.quirksmode.org/js/events_mouse.htm)
Mousedown,mouseup,click
如果使用者在一個元素上點擊,那麼最少三個事件會被觸發,順序是這樣的:
1、mousedown,當使用者在這個元素上按下滑鼠鍵的時候
2、mouseup,當使用者在這個元素上鬆開滑鼠鍵的時候
3、click,當一個mousedown和一個mouseup都在這個元素上被檢測到的時候發生
通常mousedown和mouseup比click有用。有些瀏覽器不允許你讀取onclick的事件資訊。而且有時候使用者用滑鼠做出某些動作click事件沒有跟上。
假設使用者在一個連結上按下了滑鼠鍵,然後把滑鼠挪開了並且挪開後鬆開了滑鼠鍵。那麼這時候這個連結就僅僅發生了mousedown事件。類似的,使用者在點擊滑鼠之後挪到了連結上,那麼連結就僅有mouseup發生。這兩種情況都沒有click事件發生。
這是不是一個問題取決於使用者的行為。但是你應該註冊onmousedown/up事件,除非你就是完全想click發生。
如果你用了彈出警示框的話,瀏覽器可能會丟失事件發生的軌跡和發生了多少次,會引起混亂。所以最好別用那個。
Dblclick
dblclick事件很少用。如果你要用的話一定不要把onclick和dblclick的事件處理常式註冊在一個HTML元素上。如果兩個都註冊了的話你要知道使用者到底幹什麼是一件基本上不可能的事情。
總之,當使用者在一個元素上雙擊的時候click事件總是發生在dblclick之前。另外,在Netscape中,第二個click總是會在dblclick之前被分開處理。不管怎樣,警示框在這是很危險的。
所以保證你的click和dblclick很好的分離能避免很多複雜的事情。
Mousemove
mousemove事件啟動並執行很好,但是需要注意的是那可能需要很多的系統資源來處理所有的mousemove事件。當使用者把滑鼠移動一個像素,mousemove就觸發一次。就算什麼都沒發生,長而複雜的函數也要耗費很長的時間會影響網站的效率:所有的事情都會變慢,尤其在那些老古董上。
所以最好的辦法就是當你需要的時候註冊onmousemove事件,在不用的時候儘快移除: 複製代碼 代碼如下:element.onmousemove = doSomething;
// later
element.onmousemove = null;
Mouseover和mouseout
再看看這個例子,換成mouserover然後試試。這個例子只是在ev3上添加了onmouseover的事件處理常式。然而你會注意到不僅僅在ev3上會觸發事件在ev4或者span上都會觸發。在Mozilla 1.3之前,當滑鼠進入一個文本地區的時候都會觸發。
原因當然就是事件冒泡。使用者在ev4上觸發了mouseover事件。在這個元素上沒有onmouseover事件處理常式,但是在ev3上有。所以當事件冒泡到ev3上的時候,程式就執行了。
現在這樣的設定雖然都完全正確,但是還有一個問題。首要問題就是目標。假設滑鼠進入了ev4:
-----------------------------------------
| This is div id="ev3" |
| ----------------------------- |
| | This is div id="ev4" | |
| | -------- <-------- |
| | | span | | |
| | -------- | |
| ----------------------------- |
-----------------------------------------
<--------: mouse movement
現在這個事件的target/srcElement就是ev4:就是事件發生的元素,因為滑鼠移動到了他上面。但是當下面的發生時候:
-----------------------------------------
| This is div id="ev3" |
| ----------------------------- |
| | This is div id="ev4" | |
| | -------- | |
| | | span | | |
| | | --------> | |
| | -------- | |
| ----------------------------- |
-----------------------------------------
-------->: mouse movement
這個事件的target/srcElement是一樣的。在這一樣還是滑鼠進入ev4。然而你可能會當滑鼠從ev3來或者從SPAN來的時候做不同的事。所以我們需要知道滑鼠到底從哪來的。
relatedTarget,fromElement,toElement
W3C把relatedTarget屬性加進了mouseover和mouseout事件中。在mouseover事件下就是包括滑鼠從哪來,在mouseout下就是包括滑鼠到哪去。
微軟也有包含以下資訊的兩個屬性:
1、fromElement指的是滑鼠來之前的元素。在mouseover的狀況下比較有用
2、toElement表示滑鼠將要去的那個元素。在mouseout的情況下比較有用。
在我們的第一個例子裡面,relatedTarget/fromElement包含一個ev3的引用,在我們的第二個例子是SPAN。現在你就知道滑鼠的來源了。
跨瀏覽器的代碼
所以如果你想在mouseover的情況下想知道滑鼠從哪來,那麼: 複製代碼 代碼如下:function doSomething(e) {
if (!e) var e = window.event;
var relTarg = e.relatedTarget || e.fromElement;
}
如果在mouseout的情況下想知道滑鼠的去向那麼: 複製代碼 代碼如下:function doSomething(e) {
if (!e) var e = window.event;
var relTarg = e.relatedTarget || e.toElement;
}
滑鼠離開一個層
在一個基於層的導覽功能表裡面你可能需要知道滑鼠什麼時候離開層這樣你才能把那個層關閉。所以你給這個層的onmouseout註冊了一個事件處理常式。然後事件冒泡會導致當滑鼠離開任意一個層的時候都會觸發這個onmouseout。
--------------
| Layer |.onmouseout = doSomething;
| -------- |
| | Link | ----> We want to know about this mouseout
| -------- |
| -------- |
| | Link | |
| | ----> | but not about this one
| -------- |
--------------
---->: mouse movement
另外的一個停止的方法是當你把滑鼠移入這個層,然後到了一個連結上,瀏覽器就在這個層上註冊一個mouseout事件。這個讓我很不明白(滑鼠依然在層裡),但是所有的瀏覽器都沒問題。
那麼我們如何在滑鼠真正離開的層的時候讓mouseout發生呢? 複製代碼 代碼如下:function doSomething(e) {
if (!e) var e = window.event;
var tg = (window.event) ? e.srcElement : e.target;
if (tg.nodeName != 'DIV') return;
var reltg = (e.relatedTarget) ? e.relatedTarget : e.toElement;
while (reltg != tg && reltg.nodeName != 'BODY')
reltg= reltg.parentNode
if (reltg== tg) return;
// Mouseout took place when mouse actually left layer
// Handle event
}
首先得到事件的target,也就是滑鼠離開的元素。如果target不是DIV(層),理解結束函數,因為滑鼠沒有真正離開層。
如果target是層,我們不能確定滑鼠時離開層了還是進入了層裡面的一個連結。所以要再檢查事件的relatedTarget/toElement,也就是滑鼠移向的那個元素。
我們讀取這個元素,然後我們通過DOM樹向上遍曆,直到事件的target(也就是DIV),或者BODY元素。
如果我們遇到的target是層的子項目,那麼滑鼠就沒有離開層。就停止函數的運行。
當函數通過所有的驗證我們就能確定滑鼠確實離開了層,我們就能開始應該的動作了(通常是隱藏這個層)。
Mouseenter和mouseleave
微軟還有個解決辦法。他添加了兩個新的事件mouseenter和mouseleave。除了對事件冒泡不反應以外基本上和mouseover和mouseout是一樣的。他們把註冊了事件的元素看成一個整塊,對於發生在塊內的
mouseover和mouseout不做反應。
所以這兩個事件也解決了我們的問題:他們只對綁定的元素做出mouseover/out反應。
現在這兩個事件只被版本在5.5以上的IE支援。或許其他瀏覽器哪天回借鑒下。
結尾
現在已經到了Event的介紹的尾聲了。好運!
原文地址:http://www.quirksmode.org/js/events_mouse.html
我的Twitter:@rehawk