onKeyDown事件不适用于React中的div


92

我想在React中的div上使用keyDown事件。我做:

  componentWillMount() {
      document.addEventListener("keydown", this.onKeyPressed.bind(this));
  }

  componentWillUnmount() {
      document.removeEventListener("keydown", this.onKeyPressed.bind(this));
  }      

  onKeyPressed(e) {
    console.log(e.keyCode);
  }

  render() {
    let player = this.props.boards.dungeons[this.props.boards.currentBoard].player;
    return (
      <div 
        className="player"
        style={{ position: "absolute" }}
        onKeyDown={this.onKeyPressed} // not working
      >
        <div className="light-circle">
          <div className="image-wrapper">
            <img src={IMG_URL+player.img} />
          </div>
        </div>
      </div>
    )
  }

它工作正常,但我想以React风格做更多。我试过了

        onKeyDown={this.onKeyPressed}

在组件上。但是它没有反应。我记得它在输入元素上起作用。

码笔

我该怎么做?


我个人喜欢您的方法。这看起来是将击键绑定到文档的好方法,这不在组件的范围之内。并且不需要专注于特定元素。
丹尼尔(Daniel)

Answers:


159

您应该使用tabIndex属性来侦听onKeyDownReact中div上的事件。设置会tabIndex="0"触发您的处理程序。


2
这似乎是糟糕的,过分的设计。如果我想处理容器元素上的冒泡事件但该容器本身永远不应集中怎么办?
Will P.

1
对我来说,这似乎更像是一种破解或解决方法。有时可能需要给定的div保持制表符顺序。
Iwnnay

9
tabIndex={-1}如果您正在使用非交互式元素并且不想更改文档的制表符顺序,也可以使用。
IliasT

1
您必须设置tabIndex,以使div可以集中显示。您可以设置tabIndex 0,1,-1 ....但你这样做检查了这一点之前 webaim.org/techniques/keyboard/tabindex 您可能会想设置为-1,因为你编程方式操纵它。
卡维塔

出于某种原因,这仅在我的TabIndex中的div中具有<input>元素时才有效。或其他可以重点关注的东西。就其他div而言,它仍然无法捕获。有什么想法吗?
弗利翁

23

你需要这样写

<div 
    className="player"
    style={{ position: "absolute" }}
    onKeyDown={this.onKeyPressed}
    tabIndex="0"
  >

如果onKeyPressed未绑定this,则尝试使用箭头功能重写它或将其绑定到组件中constructor


2
抱歉。我确定,我只是忽略了这一点。但这不是问题。它仍然无法正常工作。
迈克尔”

更新的答案。在按任何键之前,您应该单击div或使其聚焦。
Panther

是的 没用 我更新了上面的代码。它可以使用DOM命令正常工作,但不能使用React样式。
迈克尔”

您能解释什么不起作用吗?是您的函数没有被调用或console.log什么都不输出?
Panther

该函数未调用。我有一个Codepen:codepen.io/lafisrap/pen/OmyBYG。它涉及第275和307行。–
Michael

7

您在纯Javascript中考虑过多。摆脱那些React生命周期方法上的侦听器,并使用event.key代替event.keyCode(因为这不是JS事件对象,所以它是React SyntheticEvent)。您的整个组件可能就这么简单(假设您尚未在构造函数中绑定方法)。

onKeyPressed(e) {
  console.log(e.key);
}

render() {
  let player = this.props.boards.dungeons[this.props.boards.currentBoard].player;
  return (
    <div 
      className="player"
      style={{ position: "absolute" }}
      onKeyDown={(e) => this.onKeyPressed(e)}
    >
      <div className="light-circle">
        <div className="image-wrapper">
          <img src={IMG_URL+player.img} />
        </div>
      </div>
    </div>
  )
}

那正是我想要写的方式。但是,地狱,这是不会的。这是codepen:codepen.io/lafisrap/pen/OmyBYG。如果在第275行注释,则键盘输入(光标键)不起作用。onKeyDown在307行中。–
Michael

我用于光标键的keyCode,因为它们不返回任何字符。
迈克尔(Michael)

1
React不使用Javascript事件对象,因此没有keyCode属性。该event对象是一个React SyntheticEvent

@Michael我也不是很确定你是如何触发div上的键事件的,但是当我将这个代码放在onClickprop中而不是onKeyDown处理程序触发时,我是不确定的。

谢谢。这就解释了它……关键事件在输入字段中起作用。
Michael

1

答案与

<div 
    className="player"
    onKeyDown={this.onKeyPressed}
    tabIndex={0}
>

对我有用,请注意tabIndex需要一个数字,而不是一个字符串,因此tabIndex =“ 0”不起作用。


0

配合使用或可以使用div技巧,但只要用户将非元素的视图聚焦,您就会在整个网站上看到丑陋的聚焦轮廓。可以通过设置div使用的CSS来解决此问题tab_index="0"tabIndex="-1"outline: none焦点。

这是带有样式组件的实现:

import styled from "styled-components"

const KeyReceiver = styled.div`
  &:focus {
    outline: none;
  }
`

并在App类中:

  render() {
    return (      
      <KeyReceiver onKeyDown={this.handleKeyPress} tabIndex={-1}>
          Display stuff...
      </KeyReceiver>
    )

-1

您在构造函数中缺少方法的绑定。这就是React建议您这样做的方式:

class Whatever {
  constructor() {
    super();
    this.onKeyPressed = this.onKeyPressed.bind(this);
  }

  onKeyPressed(e) {
    // your code ...
  }

  render() {
    return (<div onKeyDown={this.onKeyPressed} />);
  }
}

还有其他方法可以执行此操作,但这将是运行时最有效的方法。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.