Javascript 鼠標(biāo)事件

2023-02-17 10:54 更新

在本章中,我們將詳細(xì)介紹鼠標(biāo)事件及其屬性。

請(qǐng)注意:此類事件不僅可能來自于“鼠標(biāo)設(shè)備”,還可能來自于對(duì)此類操作進(jìn)行了模擬以實(shí)現(xiàn)兼容性的其他設(shè)備,例如手機(jī)和平板電腦。

鼠標(biāo)事件類型

我們已經(jīng)見過了其中一些事件:

?mousedown/mouseup ?

在元素上點(diǎn)擊/釋放鼠標(biāo)按鈕。

?mouseover/mouseout ?

鼠標(biāo)指針從一個(gè)元素上移入/移出。

?mousemove ?

鼠標(biāo)在元素上的每個(gè)移動(dòng)都會(huì)觸發(fā)此事件。

?click ?

如果使用的是鼠標(biāo)左鍵,則在同一個(gè)元素上的 ?mousedown? 及 ?mouseup? 相繼觸發(fā)后,觸發(fā)該事件。

?dblclick ?

在短時(shí)間內(nèi)雙擊同一元素后觸發(fā)。如今已經(jīng)很少使用了。

?contextmenu ?

在鼠標(biāo)右鍵被按下時(shí)觸發(fā)。還有其他打開上下文菜單的方式,例如使用特殊的鍵盤按鍵,在這種情況下它也會(huì)被觸發(fā),因此它并不完全是鼠標(biāo)事件。

……還有其他幾種事件,我們稍后會(huì)學(xué)習(xí)它們。

事件順序

從上面的列表中我們可以看到,一個(gè)用戶操作可能會(huì)觸發(fā)多個(gè)事件。

例如,點(diǎn)擊鼠標(biāo)左鍵,在鼠標(biāo)左鍵被按下時(shí),會(huì)首先觸發(fā) mousedown,然后當(dāng)鼠標(biāo)左鍵被釋放時(shí),會(huì)觸發(fā) mouseup 和 click。

在單個(gè)動(dòng)作觸發(fā)多個(gè)事件時(shí),事件的順序是固定的。也就是說,會(huì)遵循 mousedown → mouseup → click 的順序調(diào)用處理程序。

鼠標(biāo)按鈕

與點(diǎn)擊相關(guān)的事件始終具有 button 屬性,該屬性允許獲取確切的鼠標(biāo)按鈕。

通常我們不在 click 和 contextmenu 事件中使用這一屬性,因?yàn)榍罢咧辉趩螕羰髽?biāo)左鍵時(shí)觸發(fā),后者只在單擊鼠標(biāo)右鍵時(shí)觸發(fā)。

不過,在 mousedown 和 mouseup 事件中則可能需要用到 event.button,因?yàn)檫@兩個(gè)事件在任何按鍵上都會(huì)觸發(fā),所以我們可以使用 button 屬性來區(qū)分是左鍵單擊還是右鍵單擊。

event.button 的所有可能值如下:

鼠標(biāo)按鍵狀態(tài) event.button
左鍵 (主要按鍵) 0
中鍵 (輔助按鍵) 1
右鍵 (次要按鍵) 2
X1 鍵 (后退按鍵) 3
X2 鍵 (前進(jìn)按鍵) 4

大多數(shù)鼠標(biāo)設(shè)備只有左鍵和右鍵,對(duì)應(yīng)的值就是 0 和 2。觸屏設(shè)備中的點(diǎn)按操作也會(huì)觸發(fā)類似的事件。

另外,還有一個(gè) event.buttons 屬性,其中以整數(shù)的形式存儲(chǔ)著當(dāng)前所有按下的鼠標(biāo)按鍵,每個(gè)按鍵一個(gè)比特位。在實(shí)際開發(fā)中,很少會(huì)用到這個(gè)屬性,如果有需要的話,你可以在 MDN 中找到更多細(xì)節(jié)。

過時(shí)的 ?event.which?

一些老代碼可能會(huì)使用 event.which 屬性來獲得按下的按鍵。這是一個(gè)古老的非標(biāo)準(zhǔn)的方式,具有以下可能值:

  • ?event.which == 1? —— 鼠標(biāo)左鍵,
  • ?event.which == 2? —— 鼠標(biāo)中鍵,
  • ?event.which == 3? —— 鼠標(biāo)右鍵。

現(xiàn)在,event.which 已經(jīng)被棄用了,不應(yīng)再使用它。

組合鍵:shift,alt,ctrl,meta

所有的鼠標(biāo)事件都包含有關(guān)按下的組合鍵的信息。

事件屬性:

  • ?shiftKey?:?Shift?
  • ?altKey?:?Alt?(或?qū)τ?Mac 是 ?Opt?)
  • ?ctrlKey?:?Ctrl?
  • ?metaKey?:對(duì)于 Mac 是 ?Cmd?

如果在事件期間按下了相應(yīng)的鍵,則它們?yōu)?nbsp;true。

比如,下面這個(gè)按鈕僅在 ?Alt+Shift?+click 時(shí)才有效:

<button id="button">Alt+Shift+Click on me!</button>

<script>
  button.onclick = function(event) {
    if (event.altKey && event.shiftKey) {
      alert('Hooray!');
    }
  };
</script>

注意:在 Mac 上我們通常使用 ?Cmd? 代替 ?Ctrl?

在 Windows 和 Linux 上有 AltShift 和 Ctrl。在 Mac 上還有:Cmd,它對(duì)應(yīng)于屬性 metaKey。

在大多數(shù)情況下,當(dāng)在 Windows/Linux 上使用 Ctrl 時(shí),在 Mac 是使用 Cmd。

也就說:當(dāng) Windows 用戶按下 Ctrl+Enter 或 Ctrl+A 時(shí),Mac 用戶會(huì)按下 Cmd+Enter 或 Cmd+A,以此類推。

因此,如果我們想支持 Ctrl+click,那么對(duì)于 Mac 應(yīng)該使用 Cmd+click。對(duì)于 Mac 用戶而言,這更舒適。

即使我們想強(qiáng)制 Mac 用戶使用 Ctrl+click —— 這非常困難。問題是:在 MacOS 上左鍵單擊和 Ctrl 一起使用會(huì)被解釋為 右鍵單擊,并且會(huì)生成 contextmenu 事件,而不是像 Windows/Linux 中的 click 事件。

因此,如果我們想讓所有操作系統(tǒng)的用戶都感到舒適,那么我們應(yīng)該將 ctrlKey 與 metaKey 一起進(jìn)行檢查。

對(duì)于 JS 代碼,這意味著我們應(yīng)該檢查 if (event.ctrlKey || event.metaKey)。

還有移動(dòng)設(shè)備

鍵盤組合是工作流的一個(gè)補(bǔ)充。這樣,如果訪客使用鍵盤操作 —— 它們就會(huì)起作用。

但是,如果訪客的設(shè)備沒有鍵盤 —— 那么這里應(yīng)該有另一種不使用鍵盤也能做到這一點(diǎn)的方式。

坐標(biāo):clientX/Y,pageX/Y

所有的鼠標(biāo)事件都提供了兩種形式的坐標(biāo):

  1. 相對(duì)于窗口的坐標(biāo):?clientX? 和 ?clientY?。
  2. 相對(duì)于文檔的坐標(biāo):?pageX? 和 ?pageY?。

我們已經(jīng)在 坐標(biāo) 中解釋過它們之間的區(qū)別。

簡(jiǎn)而言之,相對(duì)于文檔的坐標(biāo) pageX/Y 以文檔的左上角為參照物,并且同一位置的坐標(biāo)不隨頁(yè)面的滾動(dòng)而改變。相對(duì)于窗口的坐標(biāo) clientX/Y 以當(dāng)前窗口的左上角為參照物,并且同一位置的坐標(biāo)會(huì)隨著頁(yè)面的滾動(dòng)而改變。

例如,如果我們有一個(gè)大小為 500x500 的窗口,并且鼠標(biāo)在左上角,那么 clientX 和 clientY 均為 0,無論頁(yè)面如何滾動(dòng)。

如果鼠標(biāo)位于中間,那么 clientX 和 clientY 均為 250。這與它在文檔中的位置無關(guān)。在這方面,它們類似于 position:fixed。

將鼠標(biāo)移動(dòng)到輸入字段上,可以看到 clientX/clientY(此示例位于 iframe 中,因此坐標(biāo)是相對(duì)于 iframe 的):

<input onmousemove="this.value=event.clientX+':'+event.clientY" value="Mouse over me">

防止在鼠標(biāo)按下時(shí)的選擇

雙擊鼠標(biāo)會(huì)有副作用,在某些界面中可能會(huì)出現(xiàn)干擾:它會(huì)選擇文本。

比如,雙擊下面的文本,除了我們的處理程序外,還會(huì)選擇文本:

<span ondblclick="alert('dblclick')">Double-click me</span>

如果按下鼠標(biāo)左鍵,并在不松開的情況下移動(dòng)鼠標(biāo),這也常常會(huì)造成不必要的選擇。

有多種防止選擇的方法,你可以在 選擇(Selection)和范圍(Range) 一章中詳細(xì)閱讀。

在這種情況下,最合理的方式是防止瀏覽器對(duì) mousedown 進(jìn)行操作。這樣能夠阻止剛剛提到的兩種選擇:

Before...
<b ondblclick="alert('Click!')" onmousedown="return false">
  Double-click me
</b>
...After

現(xiàn)在,在雙擊時(shí),粗體元素不會(huì)被選中,并且在粗體元素上按下鼠標(biāo)左鍵也不會(huì)開始選擇。

請(qǐng)注意:其中的文本仍然是可選擇的。但是,選擇不應(yīng)該開始于該文本自身,而應(yīng)該在該文本之前或之后開始。通常,這對(duì)用戶來說挺好的。

防止復(fù)制

如果我們想禁用選擇以保護(hù)我們頁(yè)面的內(nèi)容不被復(fù)制粘貼,那么我們可以使用另一個(gè)事件:oncopy

<div oncopy="alert('Copying forbidden!');return false">
  Dear user,
  The copying is forbidden for you.
  If you know JS or HTML, then you can get everything from the page source though.
</div>

如果你試圖在 <div> 中復(fù)制一段文本,這是行不通的,因?yàn)槟J(rèn)行為 oncopy 被阻止了。

當(dāng)然,用戶可以訪問頁(yè)面的 HTML 源碼,并且可以從那里獲取內(nèi)容,但并不是每個(gè)人都知道如何做到這一點(diǎn)。

總結(jié)

鼠標(biāo)事件有以下屬性:

  • 按鈕:?button?。
  • 組合鍵(如果被按下則為 ?true?):?altKey?,?ctrlKey?,?shiftKey? 和 ?metaKey?(Mac)。
    • 如果你想處理 ?Ctrl?,那么不要忘記 Mac 用戶,他們通常使用的是 ?Cmd?,所以最好檢查 ?if (e.metaKey || e.ctrlKey)?。
  • 窗口相對(duì)坐標(biāo):?clientX/clientY?。
  • 文檔相對(duì)坐標(biāo):?pageX/pageY?。

mousedown 的默認(rèn)瀏覽器操作是文本選擇,如果它對(duì)界面不利,則應(yīng)避免它。

在下一章中,我們將看到有關(guān)鼠標(biāo)指針移動(dòng)后的事件,以及如何跟蹤其下元素變化的更多詳細(xì)信息。

任務(wù)


可選列表

重要程度: 5

創(chuàng)建一個(gè)可以選擇元素的列表,例如在文件管理器中。

  • 點(diǎn)擊列表元素,只選擇該元素(添加 ?.selected? 類),取消選擇其他所有元素。
  • 如果點(diǎn)擊時(shí),按鍵 ?Ctrl?(在 Mac 中為 ?Cmd?)是被按下的,則選擇會(huì)被切換到被點(diǎn)擊的元素上,但其他元素不會(huì)被改動(dòng)。

P.S. 對(duì)于此任務(wù),我們可以假設(shè)列表項(xiàng)是純文本的。沒有嵌套標(biāo)簽。

P.P.S. 防止點(diǎn)擊時(shí)瀏覽器原生的文本選擇。

打開一個(gè)任務(wù)沙箱。


解決方案

使用沙箱打開解決方案。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)