在 reactjs 中监听 keypress for document
Listen to keypress for document in reactjs
我想绑定以在 escape
按下时关闭活动反应 bootstrap 弹出窗口。这是代码
_handleEscKey:function(event){
console.log(event);
if(event.keyCode == 27){
this.state.activePopover.hide();
}
},
componentWillMount:function(){
BannerDataStore.addChangeListener(this._onchange);
document.addEventListener("click", this._handleDocumentClick, false);
document.addEventListener("keyPress", this._handleEscKey, false);
},
componentWillUnmount: function() {
BannerDataStore.removeChangeListener(this._onchange);
document.removeEventListener("click", this._handleDocumentClick, false);
document.removeEventListener("keyPress", this._handleEscKey, false);
},
但是当我按任意键时,控制台中没有任何记录。我也尝试在 window 上听不同的情况。'keypress'、'keyup' 等,但似乎我做错了什么。
您应该使用 keydown
而不是 keypress
。
按键(已弃用)通常仅用于根据文档生成字符输出的键
The keypress event is fired when a key is pressed down and that key normally produces a character value
The keydown event is fired when a key is pressed down.
我自己也遇到过类似的问题。我将使用您的代码来说明修复。
// for other devs who might not know keyCodes
var ESCAPE_KEY = 27;
_handleKeyDown = (event) => {
switch( event.keyCode ) {
case ESCAPE_KEY:
this.state.activePopover.hide();
break;
default:
break;
}
},
// componentWillMount deprecated in React 16.3
componentDidMount(){
BannerDataStore.addChangeListener(this._onchange);
document.addEventListener("click", this._handleDocumentClick, false);
document.addEventListener("keydown", this._handleKeyDown);
},
componentWillUnmount() {
BannerDataStore.removeChangeListener(this._onchange);
document.removeEventListener("click", this._handleDocumentClick, false);
document.removeEventListener("keydown", this._handleKeyDown);
},
由于您使用的是 createClass 做事方式,因此您不需要绑定到某些方法,因为 this
隐含在每个定义的方法中。
有一个有效的jsfiddle,使用React组件创建的createClass方法here.
我对 div 有相同的要求,可以使用 Tab 键。
我的以下代码是在对 items.map((item)=> 的调用中
...
<div
tabindex="0"
onClick={()=> update(item.id)}
onKeyDown={()=> update(item.id)}
>
{renderItem(item)}
</div>
这对我有用!
如果你可以使用 React Hooks,一个好的方法是 useEffect
,这样事件侦听器将只订阅一次,并在卸载组件时正确取消订阅。
下面的例子摘自https://usehooks.com/useEventListener/:
// Hook
function useEventListener(eventName, handler, element = window){
// Create a ref that stores handler
const savedHandler = useRef();
// Update ref.current value if handler changes.
// This allows our effect below to always get latest handler ...
// ... without us needing to pass it in effect deps array ...
// ... and potentially cause effect to re-run every render.
useEffect(() => {
savedHandler.current = handler;
}, [handler]);
useEffect(
() => {
// Make sure element supports addEventListener
// On
const isSupported = element && element.addEventListener;
if (!isSupported) return;
// Create event listener that calls handler function stored in ref
const eventListener = event => savedHandler.current(event);
// Add event listener
element.addEventListener(eventName, eventListener);
// Remove event listener on cleanup
return () => {
element.removeEventListener(eventName, eventListener);
};
},
[eventName, element] // Re-run if eventName or element changes
);
};
您也可以从 npm 安装它,例如 npm i @use-it/event-listener
- 请在此处查看项目 - https://github.com/donavon/use-event-listener.
然后,要在您的组件中使用它,您只需在功能组件中调用它并传递事件名称和处理程序。例如,如果您想在每次按下 Escape 键时 console.log
:
import useEventListener from '@use-it/event-listener'
const ESCAPE_KEYS = ['27', 'Escape'];
const App = () => {
function handler({ key }) {
if (ESCAPE_KEYS.includes(String(key))) {
console.log('Escape key pressed!');
}
}
useEventListener('keydown', handler);
return <span>hello world</span>;
}
Jt oso 的回答版本与此问题更相关。我认为这比使用外部库或 API 挂钩到 bind/unbind 侦听器的其他答案简单得多。
var KEY_ESCAPE = 27;
...
function handleKeyDown(event) {
if (event.keyCode === KEY_ESCAPE) {
/* do your action here */
}
}
...
<div onKeyDown={handleKeyDown}>
...
我想拥有全局事件侦听器,但由于使用 React Portals 而出现了奇怪的行为。尽管在文档中的门户模式组件上取消了事件,但文档元素上仍然触发了该事件。
我转向仅在包装整个组件树的根对象上使用事件侦听器。这里的问题是,最初 body 被聚焦而不是根元素,因此一旦您聚焦树中的元素,事件将首先被触发。
我寻求的解决方案是添加一个 tabindex 并使用效果挂钩自动聚焦它。
import React from "react";
export default GlobalEventContainer = ({ children, ...props }) => {
const rootRef = React.useRef(null);
useEffect(() => {
if (document.activeElement === document.body && rootContainer.current)
rootContainer.current.focus();
}
});
return <div {...props} tabIndex="0" ref={rootRef}>{children}</div>
};
我想绑定以在 escape
按下时关闭活动反应 bootstrap 弹出窗口。这是代码
_handleEscKey:function(event){
console.log(event);
if(event.keyCode == 27){
this.state.activePopover.hide();
}
},
componentWillMount:function(){
BannerDataStore.addChangeListener(this._onchange);
document.addEventListener("click", this._handleDocumentClick, false);
document.addEventListener("keyPress", this._handleEscKey, false);
},
componentWillUnmount: function() {
BannerDataStore.removeChangeListener(this._onchange);
document.removeEventListener("click", this._handleDocumentClick, false);
document.removeEventListener("keyPress", this._handleEscKey, false);
},
但是当我按任意键时,控制台中没有任何记录。我也尝试在 window 上听不同的情况。'keypress'、'keyup' 等,但似乎我做错了什么。
您应该使用 keydown
而不是 keypress
。
按键(已弃用)通常仅用于根据文档生成字符输出的键
The keypress event is fired when a key is pressed down and that key normally produces a character value
The keydown event is fired when a key is pressed down.
我自己也遇到过类似的问题。我将使用您的代码来说明修复。
// for other devs who might not know keyCodes
var ESCAPE_KEY = 27;
_handleKeyDown = (event) => {
switch( event.keyCode ) {
case ESCAPE_KEY:
this.state.activePopover.hide();
break;
default:
break;
}
},
// componentWillMount deprecated in React 16.3
componentDidMount(){
BannerDataStore.addChangeListener(this._onchange);
document.addEventListener("click", this._handleDocumentClick, false);
document.addEventListener("keydown", this._handleKeyDown);
},
componentWillUnmount() {
BannerDataStore.removeChangeListener(this._onchange);
document.removeEventListener("click", this._handleDocumentClick, false);
document.removeEventListener("keydown", this._handleKeyDown);
},
由于您使用的是 createClass 做事方式,因此您不需要绑定到某些方法,因为 this
隐含在每个定义的方法中。
有一个有效的jsfiddle,使用React组件创建的createClass方法here.
我对 div 有相同的要求,可以使用 Tab 键。
我的以下代码是在对 items.map((item)=> 的调用中 ...
<div
tabindex="0"
onClick={()=> update(item.id)}
onKeyDown={()=> update(item.id)}
>
{renderItem(item)}
</div>
这对我有用!
如果你可以使用 React Hooks,一个好的方法是 useEffect
,这样事件侦听器将只订阅一次,并在卸载组件时正确取消订阅。
下面的例子摘自https://usehooks.com/useEventListener/:
// Hook
function useEventListener(eventName, handler, element = window){
// Create a ref that stores handler
const savedHandler = useRef();
// Update ref.current value if handler changes.
// This allows our effect below to always get latest handler ...
// ... without us needing to pass it in effect deps array ...
// ... and potentially cause effect to re-run every render.
useEffect(() => {
savedHandler.current = handler;
}, [handler]);
useEffect(
() => {
// Make sure element supports addEventListener
// On
const isSupported = element && element.addEventListener;
if (!isSupported) return;
// Create event listener that calls handler function stored in ref
const eventListener = event => savedHandler.current(event);
// Add event listener
element.addEventListener(eventName, eventListener);
// Remove event listener on cleanup
return () => {
element.removeEventListener(eventName, eventListener);
};
},
[eventName, element] // Re-run if eventName or element changes
);
};
您也可以从 npm 安装它,例如 npm i @use-it/event-listener
- 请在此处查看项目 - https://github.com/donavon/use-event-listener.
然后,要在您的组件中使用它,您只需在功能组件中调用它并传递事件名称和处理程序。例如,如果您想在每次按下 Escape 键时 console.log
:
import useEventListener from '@use-it/event-listener'
const ESCAPE_KEYS = ['27', 'Escape'];
const App = () => {
function handler({ key }) {
if (ESCAPE_KEYS.includes(String(key))) {
console.log('Escape key pressed!');
}
}
useEventListener('keydown', handler);
return <span>hello world</span>;
}
Jt oso 的回答版本与此问题更相关。我认为这比使用外部库或 API 挂钩到 bind/unbind 侦听器的其他答案简单得多。
var KEY_ESCAPE = 27;
...
function handleKeyDown(event) {
if (event.keyCode === KEY_ESCAPE) {
/* do your action here */
}
}
...
<div onKeyDown={handleKeyDown}>
...
我想拥有全局事件侦听器,但由于使用 React Portals 而出现了奇怪的行为。尽管在文档中的门户模式组件上取消了事件,但文档元素上仍然触发了该事件。
我转向仅在包装整个组件树的根对象上使用事件侦听器。这里的问题是,最初 body 被聚焦而不是根元素,因此一旦您聚焦树中的元素,事件将首先被触发。
我寻求的解决方案是添加一个 tabindex 并使用效果挂钩自动聚焦它。
import React from "react";
export default GlobalEventContainer = ({ children, ...props }) => {
const rootRef = React.useRef(null);
useEffect(() => {
if (document.activeElement === document.body && rootContainer.current)
rootContainer.current.focus();
}
});
return <div {...props} tabIndex="0" ref={rootRef}>{children}</div>
};