替换已弃用的 `keypress` DOM 事件

Posted

技术标签:

【中文标题】替换已弃用的 `keypress` DOM 事件【英文标题】:Replacement for deprecated `keypress` DOM event 【发布时间】:2019-03-23 17:49:02 【问题描述】:

根据MDN article keypress 事件已被弃用:

但我在其他地方找不到任何关于我们是否应该在新项目中使用此事件的信息。如果我们不应该,替换是什么?

有人可以提供见解吗?

【问题讨论】:

@Barmar 对,我知道“弃用”是什么意思。但是,正如我在问题中提到的那样,我正在寻找有关此的任何进一步信息,例如推荐的替代品是什么(更新了问题以明确说明)。 这是我几分钟前发布的答案。 我猜替换是keyup developer.mozilla.org/en-US/docs/Web/Events/keyup @Barmar 我明白了。只是回答您的评论。 @Mohammed keyup 有点不同,所以我不确定它是否是预期的替代品。从 Barmar 的answer 来看,似乎是beforeinput 【参考方案1】:

由于该事件已被弃用,您应该避免在新代码中使用它,并计划从旧代码中删除它。 W3C specification 谈到了已弃用的功能:

标记为弃用的功能包含在规范中,作为对旧实现或规范的参考,但它们是可选的并且不鼓励使用。本规范中必须弃用已存在或正在进行替换的功能。由于与现有内容的向后兼容性,尚未包含对该功能的支持的实现可能会实现已弃用的功能,但创建内容的内容作者不应使用已弃用的功能,除非没有其他方法可以解决用例强>。引用本规范的其他规范不应使用已弃用的功能,而应指向不推荐使用该功能的替代品。本规范中标记为已弃用的功能预计将从未来的规范中删除。

keypress event 的规范说:

警告 为了参考和完整性,本规范中定义了按键事件类型,但本规范不推荐使用此事件类型。在编辑上下文中,作者可以改为订阅beforeinput 事件。

您还可以使用keydown 和/或keyup 事件。见What's the difference between keyup, keydown, keypress and input events?

但是,由于 beforeinput 还没有太多支持,如果这些其他事件都不适合您的用例,您现在必须继续使用 keypress(这是“除非没有其他方法解决规范中的用例”异常)。

【讨论】:

没错,但keydown 有点不同。在这个问题中,我试图找出何时停止使用keypress 的确切替代品。如果规范作者打算为此目的使用beforeinput,我相信它应该更精确匹配。 完全同意你的看法。非常令人失望的是,keypress 这么早就被弃用了,因为在现实世界中实际上没有提供直接替代品,这让开发人员不得不自己做出艰难的选择。 @AlexanderAbakumov - 这就是弃用的重点,警告用户避免使用该功能,在这种情况下,因为它存在互操作性问题。当然,现实情况是,没有主流浏览器会停止实现按键功能,因为这样做会破坏大量现有网站。目前这意味着你应该开始考虑如何组合使用 keydown、beforeinput、input 和 keyup 事件。您可以寻求检测 beforeinput 支持并在可用时使用它,否则回退到 keypress。 @Alohci 谢谢。只是为了更清楚地说明,我一般不反对这种弃用。但是这种特定情况的真正令人讨厌的部分是它被过早地弃用了。只有在提供了一个在相当的努力下实际上可行的替代品之后,弃用才是好的。我相信没有任何开发团队拥有使用keypress(这是限制inputs 字符集的最流行选项)的工作应用程序会尝试仅仅因为beforeinput 而搞乱keydowninputkeyup 事件尚不可用。 此答案未解决特定用例,例如 Windows 中的 Alt 键序列,其中生成的键码(例如 Alt+137 的 ë)获得 keypress 事件,但不是keyupkeydown 一个。只有单独的键 137 被报告为 keyup 和 keydown,而不是 ë。所以他们可以随心所欲地弃用它,但除非他们提供真正的替代方案,否则我们天真的前端开发人员别无选择,只能使用keypress【参考方案2】:

您可以使用keydown 事件。与 keypress 事件不同,keydown 事件为所有键触发,无论它们是否产生字符值。

const log = document.getElementById('log');

document.addEventListener('keydown', logKey);

function logKey(e) 
  log.textContent += ` $e.code`;
<p>Focus the IFrame first (e.g. by clicking in it), then try pressing some keys.</p>
<p id="log"></p>

【讨论】:

【参考方案3】:

除非(为你感到羞耻)你或你使用的东西一直在破坏事件冒泡的每一个机会,否则不是很难解决。

像这样简单但功能强大的实用程序正是您应该只对 html 的孤立节点叶子执行此操作的原因。

在您确实必须防止 keydown 冒泡的情况下,您可以简单地将以下内容包装在一个函数中,该函数需要一个参数来代替 document.body,如果您仍然想要“keypress2”,只需在冒泡停止的地方应用该 HMTL 可用的事件。

const keyBlacklist = [
    'Shift',
    'Alt',
    'Control',
    'Meta'
];

document.body.addEventListener('keydown',(e)=>
    if(keyBlacklist.indexOf(e.key) === -1)
        const newKeyPress = new CustomEvent('keypress2',detail:e);
        e.target.dispatchEvent(newKeyPress);
    
);

document.body.addEventListener('keypress2',e=>console.log(e.detail););

【讨论】:

这个答案没有解决特定的用例,例如 Windows 中的 Alt 键序列,其中生成的键码(例如,Alt+137 的 ë)获取 keypress 事件,但不是keyupkeydown 一个。只有单独的键 137 被报告为 keyup 和 keydown,而不是 ë。所以他们可以随心所欲地弃用它,但除非他们提供真正的替代方案,否则我们天真的前端开发人员别无选择,只能使用keypress

以上是关于替换已弃用的 `keypress` DOM 事件的主要内容,如果未能解决你的问题,请参考以下文章

用 .on 替换已弃用的 .live [重复]

Snapkit 常量替换已弃用的 .priorityMedium() .priorityHigh() .priorityLow()?

替换 Java Awt 已弃用的方法

什么是已弃用的 getSupportLoaderManager() 的适当替换?

jQuery:替换已弃用的“.load()”? [复制]

用 QuerydslJpaPredicateExecutor 替换已弃用的 QuerydslJpaRepository 失败