jjzjj

javascript - 事件已弃用的 KeyboardEvent.which 属性的替代方案

coder 2024-07-22 原文

MDN 声明 KeyboardEvent.which 已弃用。如何将其替换为未弃用的版本?
例如,我有以下内容:

window.onkeydown = (event) => { console.log(event.which); }
我以为 event.key.charCodeAt()可以代替event.which , 但这不适用于 ALT、CTRL 或 ENTER 等键,并且仅适用于 event.key.length === 1 :
window.onkeydown = (event) => { console.log(event.key.charCodeAt()); }
回顾一下,event.which != event.codeevent.which != event.key ,因此我无法简单地使用 event.key .event.which 有替代品吗?哪个检测组合按键,包括 ALT、CTRL 或 ENTER?

最佳答案

TL;DR:这些是您应该遵循的规则:

  • 从用户获取文本输入时,使用 keypress事件以及 e.key
  • 对于快捷方式和其他组合,内置方式是使用keydown/keyup并检查各种修饰键。如果需要检测和弦,可能需要构建状态机。

  • 背景

    键盘输入分为两个阶段 - keydown/keyup 对,它跟踪被按下的物理键,以及组合多个键序列以计算字符的组合字符。

    获取“文本”

    如果你想知道操作系统认为组合序列是什么,你应该使用 KeyboardEvent.key

    示例代码:

    document.getElementById('a').addEventListener('keypress', e => console.log(e.key));
    <input id="a" type="text" placeholder="type here">


    您大部分时间都想这样做的原因是因为许多语言通过多个按键组合字符。 US-101 键盘最容易理解的是按 shift键 + aA ,与仅按 a 相比.对于像俄语这样的语言,使用 altgr死键,这变得尤为重要。

    我要说明的一点是,自己完成所有这些工作 - 检测键序列并确定正确的文本输出是一个难题™。这是操作系统的工作是有原因的。

    现在,对于较旧的浏览器,您可能不想使用 e.key由于缺乏老年人的支持。然后你可以回退到 which 之类的东西。 ,或其他非标准方法。

    在 future 的某个时候,按键可能会被浏览器删除。 beforeinput事件应该是替换。然而,那次事件
    仅在 chrome 中受支持,因此为简洁起见,我在此省略。

    获取击键

    现在,假设您不是在跟踪文本,而是在跟踪键序列。这适用于游戏或收听 ctrl-c在这种情况下,正确的做法是收听 keydown/keyup events .对于修饰键,您只需收听 ctrlKey , shiftKey , 和 metaKey事件的属性。见下文:

    document.getElementById('a').addEventListener('keydown', (e) => {
      const states = {
        alt: e.altKey,
        ctrl: e.ctrlKey,
        meta: e.metaKey,
        shift: e.shiftKey,
      };
      const key = e.key;
      const code = e.code;
      console.log(`keydown key: ${key}, code: ${code}`, states);
    });
    <input id="a" type="text" placeholder="press ctrl">


    例如,在我的键盘上按 shift-o 时,我得到以下信息:
    keydown key: Shift, code: ShiftLeft {
      "alt": false,
      "ctrl": false,
      "meta": false,
      "shift": true
    }
    keydown key: O, code: KeyS {
      "alt": false,
      "ctrl": false,
      "meta": false,
      "shift": true
    }
    

    希望 states部分是不言而喻的。他们说在另一个键按下时是否按下了修改键。
    key 之间的区别和 code与键盘布局有关。我正在使用软件 dvorak 布局。因此,当我输入 s键,进入操作系统的扫描码显示s , 但随后操作系统将其转换为 o因为它是德沃夏克。在这种情况下,代码总是指扫描代码(被按下的物理键),而键对应于操作系统尽力找出“文本”将是什么。这并不总是可能的,尤其是对于其他语言。这也是为什么使用 keypress 的 key 的原因。是正确的方法。

    第 3 方库

    如果这听起来不是特别容易,那是因为它不是。上次我看这个时,我遇到了 mousetrap图书馆,虽然我不确定我会推荐它,但考虑到我发现的一些问题。然而,它确实展示了一个构建状态机来跟踪关键和弦的示例。

    附录

    这也是为什么您需要跟踪 keydown/keyup如果你想吃击键。由于 ctrl+c 没有“文本”,因此您将无法获得正确的按键,因此浏览器将 native 处理它。如果你想运行你自己的行为,你需要e.preventDefault()在 keydown 本身上。 (一些后续事件,如 copy 也可以取消,但并非普遍如此)

    如果您还只需要跟踪事后插入到输入字段(或内容可编辑的 div)中的键,请参阅 input事件。

    历史:
    更新 8/2019 以更改 keypress->beforeinput

    关于javascript - 事件已弃用的 KeyboardEvent.which 属性的替代方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49278648/

    有关javascript - 事件已弃用的 KeyboardEvent.which 属性的替代方案的更多相关文章

    1. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

      我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

    2. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

      我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

    3. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

      在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

    4. ruby - 多个属性的 update_column 方法 - 2

      我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

    5. ruby - Nokogiri 剥离所有属性 - 2

      我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog

    6. ruby-on-rails - Rails 模型——非持久类成员或属性? - 2

      对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs

    7. ruby-on-rails - 更好的替代方法 try( :output). try( :data). try( :name)? - 2

      “输出”是一个序列化的OpenStruct。定义标题try(:output).try(:data).try(:title)结束什么会更好?:) 最佳答案 或者只是这样:deftitleoutput.data.titlerescuenilend 关于ruby-on-rails-更好的替代方法try(:output).try(:data).try(:name)?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.c

    8. ruby-on-rails - 事件管理员日期过滤器日期格式自定义 - 2

      是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s

    9. ruby-on-rails - 事件记录 : Select max of limit - 2

      我正在尝试将以下SQL查询转换为ActiveRecord,它正在融化我的大脑。deletefromtablewhereid有什么想法吗?我想做的是限制表中的行数。所以,我想删除少于最近10个条目的所有内容。编辑:通过结合以下几个答案找到了解决方案。Temperature.where('id这给我留下了最新的10个条目。 最佳答案 从您的SQL来看,您似乎想要从表中删除前10条记录。我相信到目前为止的大多数答案都会如此。这里有两个额外的选择:基于MurifoX的版本:Table.where(:id=>Table.order(:id).

    10. ruby - Chef Ruby 遍历 .erb 模板文件中的属性 - 2

      所以这可能有点令人困惑,但请耐心等待。简而言之,我想遍历具有特定键值的所有属性,然后如果值不为空,则将它们插入到模板中。这是我的代码:属性:#===DefaultfileConfigurations#default['elasticsearch']['default']['ES_USER']=''default['elasticsearch']['default']['ES_GROUP']=''default['elasticsearch']['default']['ES_HEAP_SIZE']=''default['elasticsearch']['default']['MAX_OP

    随机推荐