如何在React中检测Esc键按下以及如何处理


124

如何在reactjs上检测Esc按键?类似于jquery

$(document).keyup(function(e) {
     if (e.keyCode == 27) { // escape key maps to keycode `27`
        // <DO YOUR WORK HERE>
    }
});

一旦检测到,我想将信息传递给组件。我有3个组件,其中最后一个活动组件需要对逃逸键的反应做出反应。

我在想一种组件激活时的注册方式

class Layout extends React.Component {
  onActive(escFunction){
    this.escFunction = escFunction;
  }
  onEscPress(){
   if(_.isFunction(this.escFunction)){
      this.escFunction()
   }
  }
  render(){
    return (
      <div class="root">
        <ActionPanel onActive={this.onActive.bind(this)}/>
        <DataPanel onActive={this.onActive.bind(this)}/>
        <ResultPanel onActive={this.onActive.bind(this)}/>
      </div>
    )
  }
}

在所有组件上

class ActionPanel extends React.Component {
  escFunction(){
   //Do whatever when esc is pressed
  }
  onActive(){
    this.props.onActive(this.escFunction.bind(this));
  }
  render(){
    return (   
      <input onKeyDown={this.onActive.bind(this)}/>
    )
  }
}

我相信这会起作用,但我认为它更像是回调。有没有更好的方法来解决这个问题?


您是否没有助焊剂实现来存储哪个是活动组件,而不是这样做呢?
本·黑尔

@BenHare:我还是很新。我正在研究迁移到React的可行性。我没有尝试过助焊剂,因此您建议我应该研究助焊剂以解决问题。PS:如何检测ESC按键?
Neo

5
只是为了澄清一下,您是否正在寻找文档级的按键检测,例如第一个代码块?还是输入字段?您可以执行任何一种操作,我只是不确定如何确定答案。例如,这是一个快速的文档级别: codepen.io/anon/pen/ZOzaPW
Brad Colthurst,2016年

文档级就可以了:)

Answers:


228

如果您正在寻找文档级别的键事件处理,那么最好在此期间进行绑定componentDidMount(如Brad Colthurst的codepen示例所示):

class ActionPanel extends React.Component {
  constructor(props){
    super(props);
    this.escFunction = this.escFunction.bind(this);
  }
  escFunction(event){
    if(event.keyCode === 27) {
      //Do whatever when esc is pressed
    }
  }
  componentDidMount(){
    document.addEventListener("keydown", this.escFunction, false);
  }
  componentWillUnmount(){
    document.removeEventListener("keydown", this.escFunction, false);
  }
  render(){
    return (   
      <input/>
    )
  }
}

请注意,您应确保在卸载时删除键事件侦听器,以防止潜在的错误和内存泄漏。

编辑:如果您正在使用挂钩,则可以使用此useEffect结构来产生类似的效果:

const ActionPanel = (props) => {
  const escFunction = useCallback((event) => {
    if(event.keyCode === 27) {
      //Do whatever when esc is pressed
    }
  }, []);

  useEffect(() => {
    document.addEventListener("keydown", escFunction, false);

    return () => {
      document.removeEventListener("keydown", escFunction, false);
    };
  }, []);

  return (   
    <input />
  )
};

6
什么是第三个参数addEventListenerremoveEventListener
jhuang

2
@jhuang developer.mozilla.org/en-US/docs/Web/API/EventTarget / ...- 可以使用useCapture
Julio Saito,

1
@jhuang是useCapture参数,它指定是否捕获通常不会冒泡的focus事件。与无关keydown,但以前不是可选的,因此通常是为了与IE <9兼容而指定的。
Chase Sandmann

我必须包装this.escFunction成类似的函数function() { this.escFunction(event) },否则它将在页面加载时执行而没有任何“ keydown”。
M3RS

1
无需将“ false”作为第三个参数。默认情况下为假。
NattyC '19

25

您将需要侦听React的转义keyCode(27):SyntheticKeyBoardEvent onKeyDown

const EscapeListen = React.createClass({
  handleKeyDown: function(e) {
    if (e.keyCode === 27) {
      console.log('You pressed the escape key!')
    }
  },

  render: function() {
    return (
      <input type='text'
             onKeyDown={this.handleKeyDown} />
    )
  }
})

问题注释中发布的Brad Colthurst的CodePen有助于查找其他按键的按键代码。


15
我认为值得补充的是,当按下的键为ESC并且焦点位于内部时,React似乎不会触发该onKeyPress事件<input type="text" />。在这种情况下,您可以使用onKeyDownonKeyUp,并按正确的顺序触发它们。
汤姆(Tom)”

12

在功能组件中完成此操作的另一种方法是使用useEffectuseFunction,如下所示:

import React, { useEffect } from 'react';

const App = () => {


  useEffect(() => {
    const handleEsc = (event) => {
       if (event.keyCode === 27) {
        console.log('Close')
      }
    };
    window.addEventListener('keydown', handleEsc);

    return () => {
      window.removeEventListener('keydown', handleEsc);
    };
  }, []);

  return(<p>Press ESC to console log "Close"</p>);
}

代替console.log,您可以useState用来触发某些东西。


7

React使用SyntheticKeyboardEvent包装本地浏览器事件,并且此Synthetic事件提供了命名的key属性
您可以像这样使用:

handleOnKeyDown = (e) => {
  if (['Enter', 'ArrowRight', 'Tab'].includes(e.key)) {
    // select item
    e.preventDefault();
  } else if (e.key === 'ArrowUp') {
    // go to top item
    e.preventDefault();
  } else if (e.key === 'ArrowDown') {
    // go to bottom item
    e.preventDefault();
  } else if (e.key === 'Escape') {
    // escape
    e.preventDefault();
  }
};

3
有趣的事实,如果你需要支持IE9和/或Firefox 36或以下,e.key对于Escape回来为Esc#triggered

4

对于可重用的React hook解决方案

import React, { useEffect } from 'react';

const useEscape = (onEscape) => {
    useEffect(() => {
        const handleEsc = (event) => {
            if (event.keyCode === 27) 
                onEscape();
        };
        window.addEventListener('keydown', handleEsc);

        return () => {
            window.removeEventListener('keydown', handleEsc);
        };
    }, []);
}

export default useEscape

用法:

const [isOpen, setIsOpen] = useState(false);
useEscape(() => setIsOpen(false))

3
该解决方案不允许更改onEscape函数。您应该使用备注,并将onEscape用作useEffect的dep数组
Neo
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.