如何在输入或孩子没有使用React聚焦时隐藏div?

时间:2017-04-05 19:22:51

标签: javascript reactjs

所以,我有一个自定义搜索和选择组件,用于呈现包含在父容器中的输入和结果列表:

<div className='wrapper'>
  <input />
  <div className='results'>
    <div>Result Item</div>
    <div>Result Item</div>
    <div>Result Item</div>
    <div>Result Item</div>
    <div>Result Item</div>
  </div>
</div>

我想要实现的是,当用户关注input时,会显示结果列表div。我是通过一个州 - isExpanded实现这一目标的。所以,我使用输入的onFocus方法:

<input onFocus={this.handleFocus} />

功能:

handleFocus = () => {
  this.setState({
    isExpanded: true
  });
}

这很有效。我遇到的问题是在适当的时候让它关闭。它只应在用户实际点击wrapper div之外时关闭。当我需要它保持开放时:

  • 如果用户点击任何结果项
  • 如果用户专注于输入,则单击结果项
  • 如果用户点击结果项,则关注输入

因此,基本上wrapper div内的任何互动都应保持开放。

为了尝试实现这一点,我在包装器周围放了一个模糊事件:

<div className='wrapper' tabIndex='1' onBlur={this.handleBlur}> ... </div>

然后是函数

handleBlur = () => {
  this.setState({
    isExpanded: false
  });
}

问题是,当点击某个项目或专注于输入时会消除该事件发生的焦点wrapper,但是当我不想要它时,我无法防止它被触发

我尝试使用与document.activeElement混合的ReactDOM.findDOMNode来比较活动元素,但它仍无法正常工作。有什么想法吗?

以下是我尝试实现的基本示例(它使用了不同的函数绑定方法,但仍然有点):

&#13;
&#13;
class SearchAndSelect extends React.Component {

  constructor() {
    super();
    this.state = {
    	isExpanded: false
    }
    this.handleBlur = this.handleBlur.bind(this);
    this.handleFocus = this.handleFocus.bind(this);
  }
  
  handleBlur() {
    this.setState({
      isExpanded: false
    })
  }
  
  handleFocus() {
    this.setState({
      isExpanded: true
    })
  }
  
  render(){
    return(
      <div className='wrapper' tabIndex='1' onBlur={this.handleBlur}>
        <input onFocus={this.handleFocus} />
        {this.state.isExpanded && <div>Results</div>}
      </div>
    );
  }

}

ReactDOM.render(<SearchAndSelect />, document.getElementById('container'));
&#13;
<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="container"></div>
&#13;
&#13;
&#13;

3 个答案:

答案 0 :(得分:1)

如果在发生模糊事件时鼠标在包装中发生故障,您可以说要忽略模糊。我已经使用this.ignoreBlur来表示是否应该忽略模糊 - 我没有使用状态,因为你不想要或不需要它来重新渲染。我还包括移出包装器以重置ignoreBlur,以防鼠标停止,你将永远不会获得包装器的鼠标启动事件,这将使ignoreBlur永久保持为真!

<div className='wrapper' onMouseDown={this.setIgnoreBlur} onMouseUp={this.clearIgnoreBlur} onMouseOut={this.clearIgnoreBlur} onBlur={this.handleBlur}>
  <input />
  <div className='results'>
    <div>Result Item</div>
    <div>Result Item</div>
    <div>Result Item</div>
    <div>Result Item</div>
    <div>Result Item</div>
  </div>
</div>

setIgnoreBlur = () => {
  this.ignoreBlur = true;
}

clearIgnoreBlur = () => {
  this.ignoreBlur = false;
}

handleBlur = () => {
  if (this.ignoreBlur) return;
  this.setState({
    isExpanded: false
  });
}

我更新了你的小提琴:https://jsfiddle.net/jwm6k66c/2474/

答案 1 :(得分:0)

我已经做了类似的事情,我通过在下面设置了一个div来实现它:

<div className='closer' onClick={this.handleBlur...
<div className='wrapper'...

.closer:
position: absolute
width/height:100%

答案 2 :(得分:0)

此高阶组件应该可以帮助您:https://github.com/kentor/react-click-outside

见那里的例子。您需要使用它增强包装器组件,然后将this.setState({ isExpanded: false })放入handleClickOutside()方法。