javascript 为 keydown 添加事件侦听器以响应元素

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/47933175/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 07:42:28  来源:igfitidea点击:

adding event listener for keydown to react element

javascriptreactjs

提问by xyious

I'm trying to add an event listener for keydownevent in an image (or div) tag. It works if I add it to the document with document.addEventListener, but it doesn't when I try to put it into the specific element that I create in react (I noted in the code what works and what doesn't). Also handleClickworks and handleKeydoes not, no matter which format I put it into the tag with.

我正在尝试为keydown图像(或 div)标签中的事件添加事件侦听器。如果我使用 将它添加到文档中它会起作用document.addEventListener,但是当我尝试将它放入我在 react 创建的特定元素时它不会(我在代码中指出了哪些有效,哪些无效)。也handleClick有效handleKey,但不管我用哪种格式将它放入标签中。

class PrescriptionImage extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      error: null,
      isLoaded: false,
      patient: "",
      rotation: 0
    };
    this.handleKey = this.handleKey.bind(this);
  }

  handleClick() {
    this.setState({rotation: this.state.rotation + 270})
  }

  handleKey(e) {
    e.preventDefault();
    console.log(e);
    if (e.code == 'ArrowLeft') {
      if (e.ctrlKey) {
        this.setState({rotation: this.state.rotation + 270})
      }
    }
  }

  componentDidMount() {
//    document.getElementById("left").addEventListener("keydown", this.handleKey, true); This doesn't work (no error)
//    this.RxImage.addEventListener("keydown", this.handleKey, false); This doesn't work, (can't find addEventListener of "undefined")
//    document.addEventListener("keydown", this.handleKey, false); This works.
    fetch("http://localhost:3333/patientAddress.json")
      .then(res => res.json())
      .then(
        result => {
          this.setState({
            isLoaded: true,
            patient: result.order.patient
          });
        },
        error => {
          this.setState({
            isLoaded: true,
            error
          });
        }
      );
  }

  componentWillUnmount(){
    document.removeEventListener("keydown", this.handleKey, false);
  }

  render() {
    const { error, isLoaded, patient, rotation } = this.state;
    if (error) {
      return <div>Error: {error.message}</div>;
    } else if (!isLoaded) {
      return <div>Loading...</div>;
    } else {
      return <img className="prescription-image" style={{width: "98%", height: "98%", transform: `rotate(${rotation}deg)`}} src={"data:image/png;base64," + patient.rx.imageData} onClick={() => this.handleClick()} onKeyDown={this.handleKey} />;
    }
  }
}

ReactDOM.render(<PrescriptionImage />, document.getElementById("left"));

回答by Sagiv b.g

You got 2 main issues here:

你在这里有两个主要问题:

  1. The keyDownevent needs the divto be in focus. one way to do it is to add a tabindexattribute to the div. after you focus on it you can trigger the onKeyDownevent on any key on the keyboard.
  2. In your handler you are trying to check for e.codebut in fact the correct property is e.keycode.
    with that said, you should carefully read about the browsers support for itas it is considered as deprecated at some browsers.
    Here is a list of the available properties of this event and their status(check keyfor example).
  1. keyDown事件需要div成为焦点。做到这一点的方法之一是一个添加tabindex属性的div。专注于它后,您可以onKeyDown在键盘上的任何键上触发事件。
  2. 在您的处理程序中,您试图检查e.code但实际上正确的属性是e.keycode.
    话虽如此,您应该仔细阅读浏览器对它的支持,因为它在某些浏览器中被视为已弃用。
    这是此事件的可用属性及其状态的列表key例如检查)。

EDIT
I have added another approach, using the ref API of react. This way you can attach an event listener the way you did before and also trigger a focus via code (see componentDidMount).

编辑
我添加了另一种方法,使用reactref API。通过这种方式,您可以像以前一样附加事件侦听器,还可以通过代码触发焦点(请参阅 参考资料componentDidMount)。

Here is a running example:

这是一个运行示例:

class App extends React.Component {

  componentDidMount() {
    this.myDiv.addEventListener('keydown', this.handleKey);
    this.myDiv.focus();
  }

  componentWillUnmount() {
    this.myDiv.removeEventListener('keydown', this.handleKey);
  }

  handleKey = e => {
    console.log(e.keyCode);
  }

  render() {
    return (
      <div>
        <div tabIndex="0" onKeyDown={this.handleKey}>click me</div>
        <div tabIndex="1" ref={ref => this.myDiv = ref}>by ref</div>
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

回答by Sergio Barbosa

This implementation worked well for me.

这个实现对我来说效果很好。

class App extends React.Component {

  constructor(props) {
    super(props);
    this.myDiv = React.createRef();
  }

  componentDidMount() {
    this.myDiv.current.addEventListener('keydown', this.handleKey);
    this.myDiv.current.focus();
  }

  componentWillUnmount() {
    this.myDiv.current.removeEventListener('keydown', this.handleKey);
  }

  handleKey = e => {
    console.log(e.keyCode);
  }

  render() {
    return (
      <div>
        <div tabIndex="0" onKeyDown={this.handleKey}>click me</div>
        <div tabIndex="1" ref={this.myDiv}>by ref</div>
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));