W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
在我們開始學習鍵盤的相關(guān)內(nèi)容之前,請注意,在現(xiàn)代設(shè)備上,還有其他“輸入內(nèi)容”的方法。例如,人們使用語音識別(尤其是在移動端設(shè)備上)或用鼠標復(fù)制/粘貼。
因此,如果我們想要跟蹤 <input>
字段中的所有輸入,那么鍵盤事件是不夠的。無論如何,還需要一個名為 input
的事件來跟蹤 <input>
字段中的更改。對于這樣的任務(wù)來說,這可能是一個更好的選擇。稍后我們將在 事件:change,input,cut,copy,paste 一章中介紹它們。
當我們想要處理鍵盤行為時,應(yīng)該使用鍵盤事件(虛擬鍵盤也算)。例如,對方向鍵 Up 和 Down 或熱鍵(包括按鍵的組合)作出反應(yīng)。
為了更好地理解鍵盤事件,你可以使用下面這個測試臺。
在文本區(qū)域中嘗試使用不同的組合鍵。
示例代碼在
當一個按鍵被按下時,會觸發(fā) keydown
事件,而當按鍵被釋放時,會觸發(fā) keyup
事件。
事件對象的 key
屬性允許獲取字符,而事件對象的 code
屬性則允許獲取“物理按鍵代碼”。
例如,同一個按鍵 Z,可以與或不與 Shift
一起按下。我們會得到兩個不同的字符:小寫的 z
和大寫的 Z
。
event.key
正是這個字符,并且它將是不同的。但是,event.code
是相同的:
Key | event.key
|
event.code
|
---|---|---|
Z | z (小寫) |
KeyZ
|
Shift+Z | Z (大寫) |
KeyZ
|
如果用戶使用不同的語言,那么切換到另一種語言將產(chǎn)生完全不同的字符,而不是 "Z"
。它將成為 event.key
的值,而 event.code
則始終都是一樣的:"KeyZ"
。
“KeyZ” 和其他按鍵代碼
每個按鍵的代碼都取決于該按鍵在鍵盤上的位置。UI 事件代碼規(guī)范 中描述了按鍵代碼。
例如:
- 字符鍵的代碼為 ?
"Key<letter>"
?:?"KeyA"
?,?"KeyB"
? 等。- 數(shù)字鍵的代碼為:?
"Digit<number>"
?:?"Digit0"
?,?"Digit1"
? 等。- 特殊按鍵的代碼為按鍵的名字:?
"Enter"
?,?"Backspace"
?,?"Tab"
? 等。有幾種廣泛應(yīng)用的鍵盤布局,該規(guī)范給出了每種布局的按鍵代碼。
有關(guān)更多按鍵代碼,請參見 規(guī)范的字母數(shù)字部分,或者只需在上面的 測試臺 中按下一個按鍵。
大小寫敏感:?
"KeyZ"
?,不是 ?"keyZ"
?這是顯而易見的,但人們?nèi)詴沐e。
請規(guī)避錯誤類型:它是
KeyZ
,而不是keyZ
。像event.code=="keyZ"
這樣的檢查不起作用:"Key"
的首字母必須大寫。
如果按鍵沒有給出任何字符呢?例如,Shift 或 F1 或其他。對于這些按鍵,它們的 event.key
與 event.code
大致相同:
Key | event.key
|
event.code
|
---|---|---|
F1 | F1
|
F1
|
Backspace | Backspace
|
Backspace
|
Shift | Shift
|
ShiftRight 或 ShiftLeft
|
請注意,event.code
準確地標明了哪個鍵被按下了。例如,大多數(shù)鍵盤有兩個 Shift 鍵,一個在左邊,一個在右邊。event.code
會準確地告訴我們按下了哪個鍵,而 event.key
對按鍵的“含義”負責:它是什么(一個 “Shift”)。
假設(shè),我們要處理一個熱鍵:Ctrl+Z(或 Mac 上的 Cmd+Z)。大多數(shù)文本編輯器將“撤銷”行為掛在其上。我們可以在 keydown
上設(shè)置一個監(jiān)聽器,并檢查哪個鍵被按下了。
這里有個難題:在這樣的監(jiān)聽器中,我們應(yīng)該檢查 event.key
的值還是 event.code
的值?
一方面,event.key
的值是一個字符,它隨語言而改變。如果訪問者在 OS 中使用多種語言,并在它們之間進行切換,那么相同的按鍵將給出不同的字符。因此檢查 event.code
會更好,因為它總是相同的。
像這樣:
document.addEventListener('keydown', function(event) {
if (event.code == 'KeyZ' && (event.ctrlKey || event.metaKey)) {
alert('Undo!')
}
});
另一方面,event.code
有一個問題。對于不同的鍵盤布局,相同的按鍵可能會具有不同的字符。
例如,下面是美式布局(“QWERTY”)和德式布局(“QWERTZ”)—— 來自 Wikipedia:
對于同一個按鍵,美式布局為 “Z”,而德式布局為 “Y”(字母被替換了)。
從字面上看,對于使用德式布局鍵盤的人來說,但他們按下 Y 時,event.code
將等于 KeyZ
。
如果我們在代碼中檢查 event.code == 'KeyZ'
,那么對于使用德式布局鍵盤的人來說,當他們按下 Y 時,這個測試就通過了。
聽起來確實很怪,但事實確實如此。規(guī)范 中明確提到了這種行為。
因此,event.code
可能由于意外的鍵盤布局而與錯誤的字符進行了匹配。不同鍵盤布局中的相同字母可能會映射到不同的物理鍵,從而導(dǎo)致了它們有不同的代碼。幸運的是,這種情況只發(fā)生在幾個代碼上,例如 keyA
,keyQ
,keyZ
(我們已經(jīng)看到了),而對于諸如 Shift
這樣的特殊按鍵沒有發(fā)生這種情況。你可以在 規(guī)范 中找到該列表。
為了可靠地跟蹤與受鍵盤布局影響的字符,使用 event.key
可能是一個更好的方式。
另一方面,event.code
的好處是,綁定到物理鍵位置的 event.code
會始終保持不變。因此,即使在切換了語言的情況下,依賴于它的熱鍵也能正常工作。
我們想要處理與布局有關(guān)的按鍵?那么 event.key
是我們必選的方式。
或者我們希望一個熱鍵即使在切換了語言后,仍能正常使用?那么 event.code
可能會更好。
如果按下一個鍵足夠長的時間,它就會開始“自動重復(fù)”:keydown
會被一次又一次地觸發(fā),然后當按鍵被釋放時,我們最終會得到 keyup
。因此,有很多 keydown
卻只有一個 keyup
是很正常的。
對于由自動重復(fù)觸發(fā)的事件,event
對象的 event.repeat
屬性被設(shè)置為 true
。
默認行為各不相同,因為鍵盤可能會觸發(fā)很多可能的東西。
例如:
Delete
? 鍵)。PageDown
? 鍵)。Ctrl+S
?)阻止對 keydown
的默認行為可以取消大多數(shù)的行為,但基于 OS 的特殊按鍵除外。例如,在 Windows 中,Alt+F4 會關(guān)閉當前瀏覽器窗口。并且無法通過在 JavaScript 中阻止默認行為來阻止它。
例如,下面的這個 <input>
期望輸入的內(nèi)容為一個電話號碼,因此它不會接受除數(shù)字,+
,()
和 -
以外的按鍵:
<script>
function checkPhoneKey(key) {
return (key >= '0' && key <= '9') || ['+','(',')','-'].includes(key);
}
</script>
<input onkeydown="return checkPhoneKey(event.key)" placeholder="請輸入手機號" type="tel">
這里 onkeydown
的處理程序使用 checkPhoneKey
來檢查被按下的按鍵。如果它是有效的(0..9
或 +-()
之一),那么將返回 true
,否則返回 false
。
我們都知道,像上面那樣,從事件處理程序返回 false
會阻止事件的默認行為,所以如果按下的按鍵未通過按鍵檢查,那么 <input>
中什么都不會出現(xiàn)(從事件處理程序返回 true
不會對任何行為產(chǎn)生影響,只有返回 false
會產(chǎn)生對應(yīng)的影響)。
請注意,像 Backspace、Left、Right 這樣的特殊按鍵在 <input>
中無效。這是嚴格過濾器 checkPhoneKey
的副作用。這些按鍵會使 checkPhoneKey
返回 false
。
讓我們將過濾條件放寬一點,允許 Left、Right、Delete 和 Backspace 按鍵:
<script>
function checkPhoneKey(key) {
return (key >= '0' && key <= '9') ||
['+','(',')','-','ArrowLeft','ArrowRight','Delete','Backspace'].includes(key);
}
</script>
<input onkeydown="return checkPhoneKey(event.key)" placeholder="Phone, please" type="tel">
現(xiàn)在方向鍵和刪除鍵都能正常使用了。
……即使我們對按鍵進行了過濾,但仍然可以使用鼠標右鍵單擊 + 粘貼來輸入任何內(nèi)容。移動端設(shè)備提供了其他輸入內(nèi)容的方式。因此,這個過濾器并不是 100% 可靠。
另一種方式是跟蹤 oninput
事件 —— 在任何修改后都會觸發(fā)此事件。這樣我們就可以檢查新的 input.value
,并在其無效時修改它/高亮顯示 <input>
?;蛘呶覀兛梢酝瑫r使用這兩個事件處理程序。
過去有一個 keypress
事件,還有事件對象的 keyCode
、charCode
和 which
屬性。
大多數(shù)瀏覽器對它們都存在兼容性問題,以致使該規(guī)范的開發(fā)者不得不棄用它們并創(chuàng)建新的現(xiàn)代的事件(本文上面所講的這些事件),除此之外別無選擇。舊的代碼仍然有效,因為瀏覽器還在支持它們,但現(xiàn)在完全沒必要再使用它們。
當使用虛擬/移動端鍵盤時,更正式一點的名字叫做 IME(Input-Method Editor),W3C 標準規(guī)定 KeyboardEvent 的 e.keyCode
應(yīng)該為 229
,并且 e.key
應(yīng)該為 "Unidentified"
。
當按下某些按鍵(例如箭頭或退格鍵)時,雖然其中一些鍵盤可能仍然使用正確的值來表示 e.key
、e.code
、e.keyCode
…,但并不能保證所有情況下都能對應(yīng)正確的值。所以你的鍵盤邏輯可能并不能保證適用于移動設(shè)備。
按一個按鍵總是會產(chǎn)生一個鍵盤事件,無論是符號鍵,還是例如 Shift 或 Ctrl 等特殊按鍵。唯一的例外是有時會出現(xiàn)在筆記本電腦的鍵盤上的 Fn 鍵。它沒有鍵盤事件,因為它通常是被在比 OS 更低的級別上實現(xiàn)的。
鍵盤事件:
keydown
? —— 在按下鍵時(如果長按按鍵,則將自動重復(fù)),keyup
? —— 釋放按鍵時。鍵盤事件的主要屬性:
code
? —— “按鍵代碼”(?"KeyA"
?,?"ArrowLeft"
? 等),特定于鍵盤上按鍵的物理位置。key
? —— 字符(?"A"
?,?"a"
? 等),對于非字符(non-character)的按鍵,通常具有與 ?code
? 相同的值。過去,鍵盤事件有時會被用于跟蹤表單字段中的用戶輸入。這并不可靠,因為輸入可能來自各種來源。我們有 input
和 change
事件來處理任何輸入(稍后我們會在 事件:change,input,cut,copy,paste 一章中進行介紹)。它們在任何類型的輸入(包括復(fù)制粘貼或語音識別)后觸發(fā)。
當我們真的想要鍵盤時,我們應(yīng)該使用鍵盤事件。例如,對熱鍵或特殊鍵作出反應(yīng)。
創(chuàng)建一個 runOnKeys(func, code1, code2, ... code_n)
函數(shù),在同時按下 code1, code2, ... code_n
鍵時運行函數(shù) func
。
例如,當按鍵 "Q"
和 "W"
被一起按下時(任何語言中,無論是否 CapsLock),下面的代碼將顯示 alert
:
runOnKeys(
() => alert("Hello!"),
"KeyQ",
"KeyW"
);
我們應(yīng)該使用兩個處理程序:document.onkeydown
和 document.onkeyup
。
讓我們創(chuàng)建一個集合 pressed = new Set()
來保存當前被按下的鍵。
第一個處理程序把當前被按下的鍵添加到集合中,而第二個處理程序?qū)⒈凰砷_的按鍵從集合中移除。我們每次在 keydown
上檢查我們是否按下了足夠多的鍵,如果是,則運行函數(shù) func
。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: