JS 事件(7)——事件類型——鼠標與滾輪事件


鼠標與滾輪事件

 

鼠標事件

“DOM3級事件”中定義了9個鼠標事件。

click:在單擊主鼠標按鈕(一般是左鍵)或者按下回車時觸發;這意味着onclick事件處理程序既可以通過鼠標也可以通過鍵盤執行。

dbclick:雙擊主鼠標按鈕(一般是左鍵)或者按下回車鍵時觸發。

mousedown:按下任意鼠標按鈕時觸發;不能通過鍵盤觸發。

mouseup:釋放鼠標按鈕時觸發;不能通過鍵盤觸發。

mouseenter:在鼠標光標從元素外部首次移動到元素范圍之內時觸發;這個事件不冒泡,而且光標移動到元素的后代元素上不會觸發;IE、Firefox9+和Opera支持這個事件。

mouseleave:在鼠標光標從元素上方移動到元素范圍之外時觸發;這個事件不冒泡,而且光標移動到元素的后代元素上不會觸發;IE、Firefox9+和Opera支持這個事件。

mousemove:在鼠標光標在元素內部移動時重復地觸發;不能通過鍵盤觸發。

mouseout:在鼠標位於一個元素上方,然后移動到另一個元素時觸發,另一個元素可以是這個元素的子元素;不能通過鍵盤觸發。

mouseover:在鼠標位於一個元素外部,然后將其首次移動到另一個元素邊界之內時觸發;不能通過鍵盤觸發。

 

只有在同一個元素上相繼觸發mousedown和mouseup,才會觸發click事件;類似地,只有在同一個元素上觸發兩次click事件,才會觸發一次dbclick事件。

這四個事件的觸發順序如下:

(1)mousedown

(2)mouseup

(3)click

(4)mousedown

(5)mouseup

(6)click

(7)dbclick

 

除了mouseenter、mouseleave、dbclick是“DOM3級事件”新增之外,其它事件都是“DOM2級事件”中定義的。

可以使用如下代碼檢測瀏覽器是否支持“DOM2級”鼠標事件:

1 var isSupported = document.implementation.hasFeature("MouseEvents", "2.0");
2 alert(isSupported);    //true

 

或者是否支持“DOM3級”鼠標事件:

1 var isSupported = document.implementation.hasFeature("MouseEvent", "3.0");
2 alert(isSupported);    //true

 

注意:“DOM3級”鼠標事件的feature名為MouseEvent;而“DOM2級”為MouseEvents。

 

客戶區坐標位置

通過事件對象event的clientX和clientY屬性,可以訪問事件發生時鼠標指針在視窗中的水平和垂直坐標。

1 event_util.addHandler(document, "click", function(event) {
2     event = event_util.getEvent(event);
3     alert("鼠標指針客戶區坐標為:水平距離—" + event.clientX + ";" + "垂直距離—" + event.clientY + "");
4 });

 

頁面坐標位置

通過事件對象event的pageX和pageY屬性,可以訪問事件發生時鼠標指針在頁面中的水平和垂直坐標。

1 event_util.addHandler(document, "click", function(event) {
2     event = event_util.getEvent(event);
3     alert("鼠標指針頁面坐標為:水平距離—" + event.pageX + ";" + "垂直距離—" + event.pageY);
4 });

 

在頁面沒有滾動的情況下,pageX和pageY的值與clientX和clientY的值相等。

 

IE中的頁面坐標位置

IE8及更早版本不支持事件對象上的頁面坐標,不過可以使用客戶區坐標和滾動信息計算出來。

需要用到document.body(混雜模式)或者document.documentElement(標准模式)中的scrollLeft和scrollTop屬性。

計算過程如下:

 1 event_util.addHandler(document, "click", function(event) {
 2     event = event_util.getEvent(event);
 3     var pageX = event.pageX;
 4     var pageY = event.pageY;
 5     if(pageX === undefined) {
 6         pageX = event.clientX + (document.body.scrollLeft || document.documentElememt.scrollLeft);
 7     };
 8     if(pageY === undefined) {
 9         pageY = event.clientY + (document.body.scrollTop || document.documentElememt.scrollTop);
10     };
11     alert("鼠標指針頁面坐標為:水平距離—" + pageX + ";" + "垂直距離—" + pageY);
12 });

 

屏幕坐標位置

通過事件對象event的screenX和screenY屬性,可以訪問事件發生時鼠標指針在屏幕中的水平和垂直坐標。

1 event_util.addHandler(document, "click", function(event) {
2     event = event_util.getEvent(event);
3     alert("鼠標指針屏幕坐標為:水平距離—" + event.screenX + ";" + "垂直距離—" + event.screenY);
4 });

 

修改鍵

Shift、Ctrl、Alt、Meta(或Windows或Cmd),它們經常被用來修改鼠標事件的行為。

DOM為此規定了4個屬性:shiftKey、ctrlKey、altKey、metaKey,表示這些修改鍵的狀態。

這些屬性中包含的都是布爾值,如果值為true,表示相應的鍵被按下。

當某個鼠標事件發生時,通過檢測這4個屬性,就能確定用戶是否按下某個修改鍵。

 1 event_util.addHandler(document, "click", function(event) {
 2     event = event_util.getEvent(event);
 3     var keys = new Array();
 4     if(event.shiftKey) {
 5         keys.push("shift");
 6     };
 7     if(event.ctrlKey) {
 8         keys.push("ctrl");
 9     };
10     if(event.altKey) {
11         keys.push("alt");
12     };
13     if(event.metaKey) {
14         keys.push("meta");
15     };
16     alert("點擊鼠標的同時按下了:" + keys.join(","));
17 });

點擊鼠標的同時按下Windows鍵,檢測不出來,為何?

IE9、Firefox、Safari、Chrome和Opera都支持這4個屬性;IE8及更早版本不支持metaKey屬性。

 

相關元素

對mouseover事件而言,事件的主目標就是獲得光標的元素,而相關元素就是失去光標的那個元素;

對mouseout事件而言,事件的主目標就是失去光標的元素,而相關元素就是獲得光標的那個元素。

DOM通過event事件對象的relatedTarget屬性提供了相關元素的信息。

這個屬性只對mouseover和mouseout事件才包含值;對於其他事件,其值為null。

IE8及之前版本不支持relatedTarget屬性,但提供相似的屬性。

在mouseover事件觸發時,IE的fromElement屬性中保存着相關元素;在mouseout事件觸發時,IE的toElement屬性中保存了相關元素。

IE9支持所有的這些屬性。

將getRelatedTarge()方法添加到event_util對象中。

 1 getRelatedTarget: function(event) {
 2     if(event.relatedTarget) {
 3         return event.relatedTarget;
 4     } else if(event.fromElement) {
 5         return event.fromElement;
 6     } else if(event.toElement) {
 7         return event.toElement;
 8     } else {
 9         return null;
10     }
11 }

 

附上完整的event_util對象的代碼:

 1 var event_util = {
 2     //添加事件
 3     addHandler: function(element, type, handler) {
 4         if(element.addEventListener) {                         
 5             element.addEventListener(type, handler, false);    
 6         } else if(element.attachEvent) {                       
 7             element.attachEvent("on" + type, handler);
 8         } else {
 9             element["on" + type] = handler;                    
10         }
11     },
12     //移除事件
13     removeHandler: function(element, type, handler) {
14         if(element.removeEventListener) {
15             element.removeEventListener(type, handler, false);
16         } else if(element.detachEvent) {
17             element.detachEvent("on" + type, handler);
18         } else {
19             element["on" + type] = null;
20         }
21     },
22     //獲取事件對象
23     getEvent: function(event) {
24         return event ? event : window.event;
25     },
26     //獲取事件目標
27     getTarget: function(event) {
28         return event.target || event.srcElement;
29     },
30     //阻止事件冒泡
31     stopPropagation: function(event) {
32         if(event.stopPropagation) {
33             event.stopPropagation();
34         } else {
35             event.cancelBubble = true;
36         }
37     },
38     //取消事件默認行為
39     preventDefault: function(event) {
40         if(event.preventDefault) {
41             event.preventDefault();
42         } else {
43             event.returnValue = false;
44         }
45     },
46     //獲取相關元素
47     getRelatedTarget: function(event) {
48         if(event.relatedTarget) {
49             return event.relatedTarget;
50         } else if(event.fromElement) {
51             return event.fromElement;
52         } else if(event.toElement) {
53             return event.toElement;
54         } else {
55             return null;
56         }
57     }
58 }
View Code

 

相關元素的示例:

1 var btn = document.getElementById("btn");
2 event_util.addHandler(btn, "mouseover", function(event) {
3     event = event_util.getEvent(event);
4     var relatedTarget = event_util.getRelatedTarget(event);
5     var target = event_util.getTarget(event);
6     alert("光標從" + relatedTarget.tagName + "移動到" + target.tagName);
7 });

注意:Javascript中的tagName都是大寫。

 

鼠標按鈕

對於mousedown和mouseup事件而言,在event事件對象中存在一個button屬性,表示按下或釋放的按鈕。

DOM中的button屬性可能有以下三個值:0,表示主鼠標按鈕;1,表示中間按鈕;2,表示次鼠標按鈕。

IE8及之前版本中,也提供button屬性,但其屬性值與DOM的不太通屬性值有很大差別。

再為event_util對象添加getButton()方法。

 1 getButton: function(event) {
 2     if(document.implementation.hasFeature("MouseEvents", "2.0")) {
 3         return event.button;
 4     } else {
 5         switch(event.button) {
 6             case 0:
 7             case 1:
 8             case 3:
 9             case 5:
10             case 7:
11                 return 0;
12             case 2:
13             case 6:
14                 return 2;
15             case 4:
16                 return 1;
17         }
18     }
19 }

通過檢測“MouseEvents”這個特性,就可以確定event對象中存在的button屬性中是否包含正確的值;如果測試失敗,說明是IE,就必須對相應的值進行規范化。

 

附上event_util對象的完整代碼:

 1 var event_util = {
 2     //添加事件
 3     addHandler: function(element, type, handler) {
 4         if(element.addEventListener) {                         
 5             element.addEventListener(type, handler, false);    
 6         } else if(element.attachEvent) {                       
 7             element.attachEvent("on" + type, handler);
 8         } else {
 9             element["on" + type] = handler;                    
10         }
11     },
12     //移除事件
13     removeHandler: function(element, type, handler) {
14         if(element.removeEventListener) {
15             element.removeEventListener(type, handler, false);
16         } else if(element.detachEvent) {
17             element.detachEvent("on" + type, handler);
18         } else {
19             element["on" + type] = null;
20         }
21     },
22     //獲取事件對象
23     getEvent: function(event) {
24         return event ? event : window.event;
25     },
26     //獲取事件目標
27     getTarget: function(event) {
28         return event.target || event.srcElement;
29     },
30     //阻止事件冒泡
31     stopPropagation: function(event) {
32         if(event.stopPropagation) {
33             event.stopPropagation();
34         } else {
35             event.cancelBubble = true;
36         }
37     },
38     //取消事件默認行為
39     preventDefault: function(event) {
40         if(event.preventDefault) {
41             event.preventDefault();
42         } else {
43             event.returnValue = false;
44         }
45     },
46     //獲取相關元素
47     getRelatedTarget: function(event) {
48         if(event.relatedTarget) {
49             return event.relatedTarget;
50         } else if(event.fromElement) {
51             return event.fromElement;
52         } else if(event.toElement) {
53             return event.toElement;
54         } else {
55             return null;
56         }
57     },
58     //獲取button屬性值
59     getButton: function(event) {
60         if(document.implementation.hasFeature("MouseEvents", "2.0")) {
61             return event.button;
62         } else {
63             switch(event.button) {
64                 case 0:
65                 case 1:
66                 case 3:
67                 case 5:
68                 case 7:
69                     return 0;
70                 case 2:
71                 case 6:
72                     return 2;
73                 case 4:
74                     return 1;
75             }
76         }
77     }
78 }
View Code

 

鼠標按鈕示例:

1 event_util.addHandler(document, "click", function(event) {
2     event = event_util.getEvent(event);
3     alert(event.button);
4 });

 

更多的事件信息

對於鼠標事件來說,detail屬性中包含一個數值,表示在給定位置上發生多少次單擊;在同一個位置上相繼發生mousedown和mouseup事件算作一次單擊。

detail從1開始計數。

如果鼠標在mousedown和mouseup事件之間移動了位置,則detail的值會被重置為0。

 

鼠標滾輪事件

mousewheel事件,可以在任何元素上觸發,最終會冒泡到document(IE8)或window(IE9、Opera、Chrome和Safari)對象。

與mousewheel事件對應的event對象除了包含鼠標事件的所有標准信息之外,還包含一個特殊的wheelDelta屬性;當用戶向前滾動鼠標滾輪時,wheelDelta是120的倍數,當用戶向后滾動鼠標滾輪時,wheelDelta是-120的倍數。

1 event_util.addHandler(document, "mousewheel", function(event) {
2     event = event_util.getEvent(event);
3     alert(event.wheelDelta);
4 });

多數情況下,只需要知道滾動鼠標滾輪的方向,而這通過檢測wheelDelta的正負號就可以確定。

 

在Opera9.5及之前版本中,wheelDelta的正負號是顛倒的;可以使用瀏覽器檢測技術來確定實際的值,如下:

1 event_util.addHandler(document, "mousewheel", function(event) {
2     event = event_util.getEvent(event);
3     var delta = (client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDelta)
4     alert(delta);
5 });

 

在Firefox瀏覽器中,支持一個名為DOMMouseScroll的事件,也是在鼠標滾輪滾動時觸發,其被視為鼠標事件,包含與鼠標事件有關的所有信息;而有關鼠標滾輪的信息則保存在detail屬性中,當向前滾動滾輪時,其值為-3的倍數,當向后滾動滾輪時,其值為3的倍數。

可以將DOMMouseScroll事件添加到頁面中的任何元素,而且該事件會冒泡到window對象。

1 event_util.addHandler(document, "DOMMouseScroll", function(event) {
2     event = event_util.getEvent(event);
3     alert(event.detail);
4 });

 

跨瀏覽器的解決方案

首先,創建一個能夠取得鼠標滾輪增量值(delta)的方法getWheelDelta()。

1 getWheelDelta: function(event) {
2     if(event.wheelDelta) {
3         return event.wheelDelta;
4     } else {
5         return -event.detail * 40;
6     }
7 }

首先檢測事件中是否包含wheelDelta屬性,如果是,則通過wheelDelta屬性返回值;如果不存在wheelDelta屬性,則假設相應的值保存在detail屬性中,將這個值取反然后乘以40,就可以得到與其它瀏覽器相同的值。

上述代碼暫不考慮Opera9.5及之前的情況。

將這個方法添加到event_util對象中;附上event_util對象完整代碼:

 1 var event_util = {
 2     //添加事件
 3     addHandler: function(element, type, handler) {
 4         if(element.addEventListener) {                         
 5             element.addEventListener(type, handler, false);    
 6         } else if(element.attachEvent) {                       
 7             element.attachEvent("on" + type, handler);
 8         } else {
 9             element["on" + type] = handler;                    
10         }
11     },
12     //移除事件
13     removeHandler: function(element, type, handler) {
14         if(element.removeEventListener) {
15             element.removeEventListener(type, handler, false);
16         } else if(element.detachEvent) {
17             element.detachEvent("on" + type, handler);
18         } else {
19             element["on" + type] = null;
20         }
21     },
22     //獲取事件對象
23     getEvent: function(event) {
24         return event ? event : window.event;
25     },
26     //獲取事件目標
27     getTarget: function(event) {
28         return event.target || event.srcElement;
29     },
30     //阻止事件冒泡
31     stopPropagation: function(event) {
32         if(event.stopPropagation) {
33             event.stopPropagation();
34         } else {
35             event.cancelBubble = true;
36         }
37     },
38     //取消事件默認行為
39     preventDefault: function(event) {
40         if(event.preventDefault) {
41             event.preventDefault();
42         } else {
43             event.returnValue = false;
44         }
45     },
46     //獲取相關元素
47     getRelatedTarget: function(event) {
48         if(event.relatedTarget) {
49             return event.relatedTarget;
50         } else if(event.fromElement) {
51             return event.fromElement;
52         } else if(event.toElement) {
53             return event.toElement;
54         } else {
55             return null;
56         }
57     },
58     //獲取button屬性值
59     getButton: function(event) {
60         if(document.implementation.hasFeature("MouseEvents", "2.0")) {
61             return event.button;
62         } else {
63             switch(event.button) {
64                 case 0:
65                 case 1:
66                 case 3:
67                 case 5:
68                 case 7:
69                     return 0;
70                 case 2:
71                 case 6:
72                     return 2;
73                 case 4:
74                     return 1;
75             }
76         }
77     },
78     //獲取鼠標滾輪增量值
79     getWheelDelta: function(event) {
80         if(event.wheelDelta) {
81             return event.wheelDelta;
82         } else {
83             return -event.detail * 40;
84         }
85     }
86 }
View Code

 

定義一個handleWheelDelta函數,作為一個事件處理程序,可以同時應對FIrefox中的“DOMMouseScroll”事件和非Firefox中的“mousewheel”事件。

1 function handleMouseWheel(event) {
2     event = event_util.getEvent(event);
3     var delta = event_util.getWheelDelta(event);
4     alert(delta);
5 }

 

可以使用以下代碼來添加事件:

1 event_util.addHandler(document, "DOMMouseScroll", handleMouseWheel);
2 event_util.addHandler(document, "mousewheel", handleMouseWheel);

 

可以進一步將這些代碼放在一個私有作用域中,從而不會讓新定義的函數干擾全局作用域。

1 (function() {
2     function handleMouseWheel(event) {
3         event = event_util.getEvent(event);
4         var delta = event_util.getWheelDelta(event);
5         alert(delta);
6     }
7     event_util.addHandler(document, "DOMMouseScroll", handleMouseWheel);
8     event_util.addHandler(document, "mousewheel", handleMouseWheel);
9 })();

 

觸摸設備

(1)不支持dbclick事件。雙擊瀏覽器窗口會放大畫面,而且沒有辦法改變該行為。

(2)輕擊可單擊元素會觸發mouseover事件。如果此操作導致內容變化,則不會再有其它事件發生;如果屏幕沒有發生變化,則依次發生mousedown、mouseup、click事件。

(3)mousemove事件也會觸發mouseover和mouseout事件。

(4)兩個手指放在屏幕上且頁面隨手指移動而滾動時會觸發mousewheel和scroll事件。

 

無障礙性問題

可以通過鍵盤上的回車鍵來觸發click事件,而其它鼠標事件都不能通過鍵盤觸發;因此,不建議使用其它鼠標事件來展示功能或引發代碼執行,因為這樣會給屏幕閱讀器用戶造成極大不便。

使用鼠標事件時應注意的幾個易訪問性問題:

(1)使用click事件執行代碼。

(2)不要使用mouseover向用戶顯示新的選項;如果確實需要通過這種方式來顯示,可以考慮添加顯示相同信息的鍵盤快捷方式。

(3)不要使用dbclick執行重要的操作;鍵盤無法觸發這個事件。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM