React tabIndex onBlur不要隐藏元素

时间:2018-03-29 14:58:53

标签: reactjs dom

我有一个侧边栏元素,使用tabIndexonBlur来控制可见性,因此当用户选择侧边栏之外的任何内容时,它会自动隐藏。

这很有效,但我需要在侧边栏中添加一个下拉菜单,然后获取focus并导致边栏折叠(在用户选择之前)。

state = {
  visible: true
}

componentDidMount () {
  this.focusSidebar()
}

componentDidUpdate () {
  if (this.state.visible) this.focusSidebar()
}

focusSidebar () {
  ReactDOM.findDOMNode(this.refs.sidebarRegion).focus()
}

hideSidebar () => {
  this.setState({ visible: false })
}

render () {
  return (
    <div
      onBlur={this.hideSidebar}
      tabIndex='0'
      className={`sidebar ${this.state.visible ? '' : 'hidden'}`}
      ref='sidebarRegion'
    >
      <select>
        <option>Foo</option>
      </select>
    </div>
  )
}

我没有看到使用我目前的侧边栏实现来处理这个问题的好方法,但是我试图找到一种方法来自我控制侧边栏元素而无需提升可见/隐藏在组件之外的状态。

1 个答案:

答案 0 :(得分:2)

您可以使用document.activeElement来达到您想要的效果。我不会添加更多详细信息,因为它已经解释为here。您还可以查看this gist

这里用你的代码演示,我没有添加css,而是一个控制台日志告诉你什么时候应该隐藏:

class Hello extends React.Component {
 state = {
  visible: true
}

componentDidMount () {
  this.focusSidebar()
}

componentDidUpdate () {
  if (this.state.visible) this.focusSidebar()
}

focusSidebar () {
  ReactDOM.findDOMNode(this.refs.sidebarRegion).focus()
}

hideSidebar(e) {
  var currentTarget = e.currentTarget;
  setTimeout(()=>{
    if (!currentTarget.contains(document.activeElement)) {
      this.setState({ visible: false })
      console.log("Hiding the sidebar!");
    }
}, 0);
}

render () {
  return (
    <div
      onBlur={this.hideSidebar.bind(this)}
      tabIndex='0'
      className={`sidebar ${this.state.visible ? '' : 'hidden'}`}
      ref='sidebarRegion'
    >
      <select>
        <option>Foo</option>
      </select>
    </div>
  )
}
}

ReactDOM.render(
  <Hello name="World" />,
  document.getElementById('container')
);
<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">
    <!-- This element's contents will be replaced with your component. -->
</div>