在ReactJS中检测输入元素是否处于焦点状态

118

如何在ReactJS的渲染函数中检测类似以下输入元素当前是否处于焦点状态?

<input type="text" style={searchBoxStyle} placeholder="Search"></input>   
7个回答

210

只要输入节点已经挂载并且有引用,您可以检查document.activeElement

const searchInput = React.useRef(null)

if (document.activeElement === searchInput.current) {
  // do something
}

return <input type="text" ref={searchInput} />

另一种方法是在输入框内添加事件监听器来监听focusblur事件:

const [focused, setFocused] = React.useState(false)
const onFocus = () => setFocused(true)
const onBlur = () => setFocused(false)

return <input type="text" onFocus={onFocus} onBlur={onBlur} />
请注意,每次节点聚焦或失焦时都会调用重新渲染(但这正是您想要的,对吗?)

1
对于那些在多年后查看此帖子的人:在 React 16.x 及更高版本中,不再建议使用此方式来使用“refs”,应该使用新的“React.createRef()”功能。更多信息请参见:https://reactjs.org/docs/refs-and-the-dom.html - Manuel

20

我从David给出的答案开始,他描述了两种方法,它们都对我有效,但我对两者都有疑虑:

  1. 第一种情况使用findDOMNode,这有一些缺点:最起码它的使用是不被鼓励的,并且很容易实现成反模式;此外,它也可能使代码变慢,通过绕过虚拟DOM并直接与DOM交互。

  2. 在第二个选项中,仅为查找答案创建和管理组件状态似乎太费力了,容易失去同步,并可能导致组件不必要地重新渲染。

因此,在尝试更深入地探讨该问题后,我想出了以下解决方案:

if (this.props.id === document.activeElement.id) {
  // your code goes here
}

对David回答的评论同样适用:

不应该在render方法中这样做,因为输入节点可能还没有挂载。使用像componentDidUpdatecomponentDidMount这样的生命周期方法。

优点:

  • 使用当前组件属性(这些属性是不可变的值)
  • 不需要状态管理,因此不会导致不必要的重新渲染
  • 不需要DOM遍历,因此性能应该是最好的
  • 不需要创建组件引用

要求:

  • 你的组件应该有一个传递给你想要检查的表单元素的id属性(大多数情况下应该是这样的)

12

使用钩子:

首先创建并初始化您的参考文献

const yourElement = useRef(null)

然后,您使用刚创建的引用为元素打标签:

<div ref={yourElement}>Im an DOM node</div>

然后,您可以使用此逻辑来比较document.activeElement文档属性是否等于您所引用的DOM节点。

yourElement.current === document.activeElement

10
使用hooks可以更简单地实现。导入一个模块:
import React, {useState} from "react";

定义:
const [isMyInputFocused, setIsMyInputFocused] = useState(false);

在您选择的输入中,只需添加以下内容:
onBlur={() => setIsMyInputFocused(false)}
onFocus={() => setIsMyInputFocused(true)}

从现在开始,您可以随意访问isMyInputFocused

3
这是一个“伪关注”,不会很好地扩展:例如:如果有10个输入,您将不得不提升此状态并开始管理引用,否则此状态需要应用于每个输入,并存在失去同步的风险。 - user1095118
1
非常棒的答案,谢谢您。我正在为单一用途的兄弟姐妹关系使用它,所以对我来说这很好用。 - Harry

1
使用功能组件,您可以确定当前输入是否具有焦点。
import React from "react";

export default function App() {
  const ref = React.createRef(null);

  const handleMouseOut = (currentRef) => {

    if (document.activeElement === currentRef) {
      console.log("Yesss");
    }
  };
  return (
    <div className="App">
      <input
        type="text"
        ref={ref}
        onMouseOut={() => handleMouseOut(ref.current)}
      />
    </div>
  );
}

Edit Invisible Backdrop


0
根据您想要实现的功能,您可以使用onFocus(React 17)或onBlur(React 16)来实现这些内容在焦点时所需的功能。

0

***根据@Abhishek E H的回答进行调整,如果您使用onMouseOut会有一点延迟,但使用onFocus完全没有问题。 感谢您的启发。


import React from "react";

 export default function App() {
   const ref = React.createRef(null);

   const handleMouseOut = (currentRef) => {

if (document.activeElement === currentRef) {
  console.log("Yess");
   }
 };
return (
<div className="App">
  <input
    type="text"
    ref={ref}
    onFocus={() => handleMouseOut(ref.current)}
  />
</div>

); }


这个答案和你提到的那个完全一样,只是格式不好,是吗? - Moritz Ringler
几乎完全一样,但我将 onMouseOut 更改为 onFocus,因为 onFocus 会立即更新 handleMouseOut,而 onMouseOut 则存在延迟。 - Rasaq Ganiyu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接