JavaScript keydown事件總結

luckness發表於2022-03-19

最近在開發過程中遇到了一個問題,感覺可以通過監聽keydown事件來解決。但是,在實踐的過程中發現,我原先對於keydown事件的理解並不是很正確。所以,在詳細瞭解過keydown事件之後,在此做個總結。

本文主要包括以下幾個方面的內容:

  1. 遇到的問題
  2. keydown事件
  3. 解決方案

遇到的問題

在開發過程中,我遇到這樣一個需求:

當滑鼠懸浮在目標dom上的時候,滑鼠需要設定成特殊的樣式:

  1. 沒有按住ctrl鍵,滑鼠樣式設定成樣式1;
  2. 按住ctrl鍵,滑鼠樣式設定成樣式2。

我的第一想法是,通過監聽mousemove事件來判斷滑鼠是否懸浮在目標dom上。然後通過event.ctrlKey來判斷此時是否按住了ctrl鍵:

  1. 如果沒有按住,處理上述情況1;
  2. 如果按住了,處理上述情況2。

但是,只監聽mousemove事件不能覆蓋所有的情況。比如,首先把滑鼠移動到目標dom上,此時滑鼠不動,按下或者鬆開ctrl鍵,此時滑鼠的樣式是需要變化的。但是,我們在按下或者鬆開ctrl鍵之後並沒有移動滑鼠,所以不會觸發mousemove事件。

所以,我就想通過keydown和keyup事件來監聽ctrl鍵的按下和鬆開事件。

首先,我給目標dom新增了keydown事件。這時,問題就來了:keydown事件根本就沒有觸發。

然後,我就想試試在body上繫結keydown事件,然後通過判斷event.target是否是目標dom來判斷滑鼠位置。

最後,我發現event.target是body元素,而不是我想要的目標dom。所以,我就開始查詢資料,發現keydown事件原來和我想象中的不一樣。

keydown事件

通過查閱MDN上的keydown事件,發現該事件有如下限制

Keyboard events are only generated by <inputs>, <textarea> and anything with the contentEditable attribute or with tabindex="-1".

首先我的目標dom不是inputtextarea元素,所以就考慮新增contentEditable或者tabindex屬性。

首先,我們看下contentEditable屬性。當把這個元素設定成可編輯之後(不可編輯態不會觸發keydown事件),元素的內容就可以像textarea一樣進行編輯了,這個不是我要的功能,所以這種方式不行。

然後,可以設定tabindex="-1"。此時,在一定條件下,是可以觸發keydown事件的。這個一定條件就是,首先通過點選操作讓目標dom處於focus的狀態,此時再按下ctrl鍵才會觸發keydown事件。顯然,這種方式也不能滿足需求。

此時,我們先思考一個問題:為什麼在第一部分給body新增keydown事件是可以的。我們已知的資訊是:

  1. keyboard事件觸發的條件:特殊元素,contentEditable,tabindex="-1"。

所以,我懷疑body元素設定了tabindex屬性:

document.body.tabIndex // -1

果然如此!

前面我們有說到,只有當dom處於focus狀態下的時候,按下ctrl鍵才會觸發keydown事件。那麼,對於body元素是不是也是這樣的呢?

首先,我們退出頁面的全屏模式,然後點選不屬於瀏覽器的地方。此時,瀏覽器頁面處於失去焦點的狀態。

我們把滑鼠重新移動到頁面的內容區域(注意,只是移動過去,不要點選)。然後,按下ctrl鍵,你會發現keydown事件同樣沒有觸發。

但是,對於body元素來說,先觸發focus事件並不是一個問題。在剛才頁面失去焦點的情況下,把滑鼠移動到頁面上有hover效果的元素上,發現這些元素的hover效果同樣不會觸發。所以,頁面操作的預設前提應該就是頁面處於focus狀態。這樣對於body元素來說,keydown事件觸發前首先進行focus操作就不是一個特殊的操作了。

解決方案

通過上述部分的內容,我們知道可以監聽body元素的keydown事件。那麼,接下來的問題就變成了怎麼結合body的keydown事件來判斷ctrl鍵按下或者鬆開的時候,滑鼠是否正好在目標dom上。

我是通過監聽document元素的mousemove事件來解決的。當mousemove事件觸發的時候,把event.target儲存在一個全域性變數中。當body的keydown事件觸發的時候,通過判斷這個全域性變數是否是目標dom來控制後續邏輯。ctrl鍵鬆開的邏輯同理,通過body的keyup事件來監聽。

總結

希望大家能有所收穫。如有錯誤,歡迎留言討論。

相關文章