onKeyPress与onKeyUp和onKeyDown的区别

481

这三个事件有什么区别?通过谷歌搜索,我发现:

  • onKeyDown 事件在用户按下键时触发。
  • onKeyUp 事件在用户释放键时触发。
  • onKeyPress 事件在用户按下并释放键(即先触发 onKeyDown,再触发 onKeyUp)时触发。

我理解前两个事件,但是 onKeyPress 不就和 onKeyUp 一样吗?有可能只释放键(onKeyUp)而不按下键(onKeyDown)吗?

这有点令人困惑,请有经验的人帮忙解答一下?


4
我发现如果按住TAB键,它会持续循环遍历所有字段,并仅触发'onkeydown'。 - nu everest
38
keypress事件代表了一个被输入的字符,例如'a'、'D'、'£'、'©'等。另一方面,keydown和keyup事件代表任何键被输入,包括退格、制表符、上下箭头、home、end等键。 - skcin7
4
是的。例如,Tab键:KeyUp事件可能不会被与KeyDown相同的元素捕获。 - Self Evident
14个回答

319

注意:现在已经弃用KeyPress事件,请使用KeyDown代替。

KeyPressKeyUpKeyDown分别类似于:ClickMouseUpMouseDown

  1. Down首先发生
  2. Press次之(输入文本时)
  3. Up最后发生(文本输入完成时)。

例外是webkit,其中有一个额外的事件:

keydown
keypress
textInput     
keyup
以下是一个代码片段,您可以使用它自行查看事件何时被触发:

window.addEventListener("keyup", log);
window.addEventListener("keypress", log);
window.addEventListener("keydown", log);

function log(event){
  console.log( event.type );
}


1
那么,KeyPress只是在KeyDown和TextInput之间的额外事件吗?开发人员通常如何使用它(KeyPress)? - instantsetsuna
106
+1最佳答案- 在文本输入过程中,先发生“按下(Down)”事件,然后是“按住(Press)”事件(当文本被输入时),最后发生“松开(Up)”事件(当文本输入完成时)。 - Scott Pelak
5
-1 是因为在代码片段中进行了一些实验,这与您对“点击”事件的类比相矛盾。 “点击”事件与“mouseup”(当您释放鼠标按钮时)同时触发,但“keypress”事件与“keydown”(当按键首次按下时)同时触发。 - Mark Amery
5
实际上,“keypress”和“keydown”事件被分配了相同的“.timeStamp”值,这个值精确到5微秒的间隔,但这并不是我的重点。我的重点是,“click”事件只有在你松开鼠标按钮之后才会触发,因此说“keypress”是“click”的键盘版让它听起来像“keypress”也不会在你释放按键之前触发。事实上,并非如此:它会在按下键时触发,就像“keydown”一样。因此,“keypress”实际上根本不类似于“click”。 - Mark Amery
4
“如何解释在“keydown”之后始终记录“keypress”事件?”- 简单来说,同一用户操作(按下一个键)立即触发将两个处理程序推入事件队列,但以固定顺序排列。“你只是想为了争辩而争辩”- 嗯?您回答的核心论点是keypresskeyupkeydown类比于clickmouseupmousedown。对我来说,这个自然的解释是keypress事件与keyup同时触发(就像clickmouseup)。如果不是这样,那么您当时的意思是什么? - Mark Amery
显示剩余5条评论

241

请查看此链接以获取存档的原始回答。

从该链接中可以得知:

理论上,onKeyDownonKeyUp 事件代表按下或释放键,而 onKeyPress 事件则代表输入字符。但是不同浏览器的实现并不相同。


25
根据@Falk的帖子,制作一个基于jsfiddle的示例以演示独特性(使用jquery):http://jsfiddle.net/zG9MF/2/ - fordareh
1
我看不到链接的页面,但如果您计划将其用于任何验证,那么“输入字符”这一点非常重要。keypress事件在用户“删除”字符时不会触发,因此您的验证不会生效。 - Tony Merryfield
1
@dcp - 是的,这足以让我找到正确的方向。我只是添加了我的评论来强调事件仅在键入字符时触发,而不是任何按键 - 你得到了我的赞同 ;) - Tony Merryfield
1
此外,在按键“长按”时,KeyDown事件会持续触发,直到松开按键,此时KeyUp事件仅触发一次 ;) - Youp Bernoulli
1
keypress已被弃用 https://developer.cdn.mozilla.net/en-US/docs/Web/API/Element/keypress_event - rofrol
显示剩余3条评论

49
这里大部分回答都更注重理论而非实际问题,关于输入字段的值,keyupkeypress 之间存在一些重要的差异,至少在 Firefox 中(测试版本为 43)。
如果用户在空输入框中输入了 1
  1. keypress 处理程序中输入框的值将是一个空字符串(旧值)。

  2. keyup 处理程序中输入框的值将是新值 1

这对于检测输入后的新值而非当前值的操作非常重要,例如行内验证或自动换行。
场景:
  1. 用户在输入框中键入了 12345
  2. 用户选择了文本 12345
  3. 用户键入字母 A
当输入字母 A 后触发 keypress 事件时,文本框中仅包含字母 A
但是:
  1. Field.val() 的值为 12345
  2. $Field.val().length 的值为 5
  3. 用户选择为空字符串(无法确定被覆盖的内容)。
因此,浏览器(Firefox 43)先擦除用户的选择,然后触发 keypress 事件,接着更新字段内容,最后触发 keyup

30
首先,它们有不同的意义:它们触发的时机如下:
  • KeyDown – 当按键被按下时触发
  • KeyUp – 在按键被释放后触发,并且在输入框/文本区域的值更新之后(在这些事件中仅有这一个)
  • KeyPress – 介于上述两者之间,并不意味着“按下并释放了一个按键”(请参考下文)。不仅其语义不一致,而且已经被弃用,所以可能不应该使用它(另请参阅此处的总结)。

其次,某些按键会触发其中一些事件,但不会触发其他事件。例如,

  • KeyPress 在按下键盘时会忽略 delete、箭头、PgUp/PgDnhome/endctrlaltshift 等按键,而 KeyDown 和 KeyUp 则不会(关于 esc 的详细信息请参见下文);
  • 当您在 Windows 中通过 alt+tab 切换窗口时,只有 alt 的 KeyDown 事件会触发,因为窗口切换会在任何其他事件之前发生(至少在 Chrome 71 中,tab 的 KeyDown 事件被系统阻止了)。
另外,您应该记住,在 KeyDown 和 KeyUp 事件中,event.keyCode(和 event.which)通常具有相同的值,但在 KeyPress 中则不同。试试我创建的playground。顺便说一下,我注意到一个小问题:在 Chrome 中,当我按下 ctrl+a 并且 input/textarea 为空时,KeyPress 会触发并且 event.keyCode(和 event.which)等于 1! (当输入不为空时,它根本不会触发)。
注意:现在使用event.keyevent.code是最有用的选项,因为它在浏览器、操作系统和事件中都是标准化的(据我所知),而event.whichevent.keyCode已经被弃用(12)。
最后,还有一些实用技巧:
  • 处理箭头时,您可能需要使用onKeyDown:如果用户按住,KeyDown会多次触发(而KeyUp仅在释放按钮时触发一次)。此外,在某些情况下,您可以轻松防止KeyDown的传播,但无法(或不容易)防止KeyUp的传播(例如,如果您想在不向文本字段添加换行符的情况下提交回车键)。
  • 令人惊讶的是,当您按住一个键时,比如在textarea中,KeyPress和KeyDown都会多次触发(Chrome 71),如果我需要多次触发的事件,我会使用KeyDown,单个键释放则使用KeyUp。
  • 对于游戏来说,KeyDown通常更好,因为您必须提供更好的响应性。
  • esc通常通过KeyDown进行处理:KeyPress不会触发,而KeyUp在不同浏览器中的inputtextarea的行为不同(主要是由于失去焦点)
  • 如果您想调整文本区域的高度以适应内容,则可能不会使用onKeyDown,而是使用onKeyPress(PS ok,实际上最好使用onChange)。

我在我的项目中使用了所有3种,但不幸的是可能忘记了某些实用技巧。(请注意:还有和事件)


我之前没有考虑到keyup会将换行符添加到字段内容中,但这实际上非常重要。 - FKEinternet

20

onkeydown在按下键时触发(例如快捷键中的Ctrl+A,其中保持'按下'状态的是Ctrl)。

onkeyup在释放键后触发(包括修改键/等键)。

onkeypress作为onkeydownonkeyup的组合触发,或者根据键盘重复触发(当onkeyup未触发)。 (这种重复行为是我没有测试过的。如果您进行了测试,请添加注释!)

textInput(仅适用于WebKit)在输入一些文本时触发(例如,Shift+A会输入大写字母'A',但是Ctrl+A将选择文本而不输入任何文本输入内容。在这种情况下,所有其他事件都会被触发)


1
刚刚确认了一下,确实当按键被按住时会重复调用“onkeypress”,并且会发生“键盘重复”。然而,“onkeydown”也是如此!(这个名字有点出乎意料) - Venryx

14

这篇由Jan Wolter撰写的文章是我所见过最好的,如果链接失效,可以在此处找到存档副本

它清楚地解释了所有浏览器键盘事件,

keydown事件在按下按键时立即发生,随后紧接着会生成keypress事件。当松开按键时,会生成keyup事件。

理解keydownkeypress之间的区别,有助于区分字符。一个是计算机键盘上的物理按钮。通过按下按钮来输入一个符号称为字符。在美式键盘上,按下Shift键并同时按下4键通常会产生一个“美元”符号。但这并不一定适用于世界上的所有键盘。理论上,keydownkeyup事件表示按下或释放键,而keypress事件表示键入一个字符。但实际上,并非总是这样实现。

一段时间内,一些浏览器会在keypress事件后立即发出一个称为textInput的附加事件。DOM3标准的早期版本旨在将其作为keypress事件的替代,但整个概念后来被撤销了。Webkit在525到533版本之间支持此功能,我被告知IE也支持它,但我从未检测到,可能是因为Webkit要求它被称为textInput而IE称其为textinput

所有浏览器都支持一种名为input的事件,该事件在对textarea或输入字段进行更改后立即触发。通常,会先触发keypress事件,然后键入的字符将出现在文本区域中,然后才会触发input事件。实际上,input事件并不提供任何关于所键入的键的信息 - 您必须检查文本框才能找出更改了什么 - 因此我们不认为它是一个按键事件,并且在这里也没有详细说明。虽然最初只定义用于文本区域和输入框,但我相信有一些运动朝向在其他类型的对象上触发该事件。


最佳答案,那么你如何从按键中获取美元符号呢? - B''H Bi'ezras -- Boruch Hashem

10

看起来,onkeypress和onkeydown是相同的(在上面已经提到的快捷键的小差异中)。

你可以尝试这个:

<textarea type="text" onkeypress="this.value=this.value + 'onkeypress '"></textarea>
<textarea type="text" onkeydown="this.value=this.value + 'onkeydown '" ></textarea>
<textarea type="text" onkeyup="this.value=this.value + 'onkeyup '" ></textarea>

你会发现 onkeypress 和 onkeydown 事件在按下按键时被触发,而不是按键被松开时被触发。

它们的区别在于事件不仅仅被触发一次,而是多次触发(只要你按着键不放)。请注意这一点并相应地进行处理。


1
Ctrl、Shift、CapsLock、Backspace以及其他不会输入任何字符的按键不会触发keypress事件,但它们总是会触发keydown事件 - CPHPython

10

更新的答案:

KeyDown

  • 按住键时会多次触发。
  • 会触发 meta 键。

KeyPress

  • 按住键时会多次触发。
  • 不会触发 meta 键。

KeyUp

  • 在释放键的末尾只会触发一次。
  • 会触发 meta 键。

这是在addEventListenerjQuery中的行为。

https://jsbin.com/vebaholamu/1/edit?js,console,output <-- 尝试示例

显示了按住 SSS 的示例

(答案已经通过正确的回答、截图和示例进行了编辑)


除了 keydown 会多次触发之外,其他都可以。 - B''H Bi'ezras -- Boruch Hashem
-1,因为至少在Chrome中有至少一个细节是错误的;正如@bluejayke所说,当你按住一个键时,KeyDown事件也会重复触发。 - Mark Amery
是的,你们是对的,抱歉我的错误;回答已编辑。 - Quang Van
keypress事件在每添加一个字符时触发,而keydown事件则会持续触发(在相同的时间内取决于重复速度而触发更多次)。 - Gabriel Petersson

8

在所有浏览器中,除了ALT、CTRL、SHIFT、ESC键外,onkeypress事件适用于所有键,而onkeydown事件适用于所有键。这意味着onkeydown事件可以捕获所有按键。


按键也会忽略删除、箭头、Home/End、PgUp/PgDn等功能,详细信息请参考我的回答(你可能也需要更新你的回答)。 - YakovL

4

我想分享一个有趣的事情:

当使用onkeydown事件激活JS方法时,该事件的charcode与使用onkeypress时获得的charcode不同!

例如,使用onkeypress时,数字键盘上的键将返回与字母键上方的数字键相同的charcodes,但是在使用onkeydown时不会返回相同的charcodes!

当我使用onkeydown时检查特定charcodes的脚本失败时,我花了很多时间才弄清楚原因!

演示:https://www.w3schools.com/code/tryit.asp?filename=FMMBXKZLP1MK

是的。 我知道方法的定义是不同的..但非常令人困惑的是,在两种方法中,事件的结果都是使用event.keyCode检索的..但它们不返回相同的值..这不是一种非常明确的实现。


看起来数字字符(0123456789)的情况是一样的。 - Mrigank Pawagi
你是否注意到,keyDown 给出键盘上的 KEY,而 keyPress 给出我们刚刚输入(或点击)的确切字符? - Mrigank Pawagi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接