点击或在菜单区域外悬停时关闭反应按钮下拉菜单

Lok*_*wal 2 html javascript css reactjs

在我的反应应用程序中,其中一个组件正在创建一个按钮下拉菜单,如下所示.

<div class="dropdown">
    <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Dropdown Example
    <span class="caret"></span></button>
    <ul class="dropdown-menu">
      <li><a onClick=doSomething href="#">HTML</a></li>
      <li><a onClick=doSomething href="#">CSS</a></li>
      <li><a onClick=doSomething href="#">JavaScript</a></li>
    </ul>   
</div>
Run Code Online (Sandbox Code Playgroud)

如果有人点击/悬停在此菜单区域外的任何位置,我该如何关闭此菜单?

Sag*_*b.g 7

不要在你的React中使用jQuery事件和DOM操作,你会忽略这一点.
你state有用它!

在下面的例子中,你可以看到我删除了所有jquery.js与bootstrap.js文件,只有不停bootstrap.css.
我用的是state为了显示/隐藏<ul>列表(我已经将其设置为display: block以覆盖默认display: none的bootstrap.css).
我已经设置了2个主要处理程序,用于显示和隐藏每个项目的<ul>1个处理程序onclick:

  1. toggleShow()- 切换附加到按钮的show属性.stateonBlur
  2. hide()- 隐藏<ul>当然的状态(它还会做一件我要解释的事情).
  3. doSomething() - 单击某个项目时将触发.

这种情况有一个很好的挑战,当我们隐藏时,<ul>我们无法处理click事件.

但为什么?

因为我们并没有真正隐藏它,所以当它state.show为false 时它不会被渲染.所以基本上存在一种setState触发器的竞争条件,即对doSomething无法运行的事件处理程序的处理程序进行重新渲染.
所以这里的挑战是确定触发onBlur按钮事件的活动元素是否是内部的项目<ul>.如果是,那么我们需要让项目触发它的onClick事件,然后才设置状态并"隐藏".
我们在relatedTarget附加的帮助下做到了这一点event.这是我们正在寻找的活跃元素,如果我们有一个而它不是,null那么我们触发它的click事件(无论我们不关心它的方式是什么元素),然后我们才设置状态与show: false.

一个工作的例子:

class DropDown extends React.Component{
  constructor(props){
    super(props);

    this.state = {
      show: false
    }
    this.doSomething = this.doSomething.bind(this);
    this.toggleShow = this.toggleShow.bind(this);
    this.hide = this.hide.bind(this);
  }

  doSomething(e){
    e.preventDefault();
    console.log(e.target.innerHTML);
  }

  toggleShow(){
    this.setState({show: !this.state.show});
  }

  hide(e){
    if(e && e.relatedTarget){
      e.relatedTarget.click();
    }
    this.setState({show: false});
  }
  
  render(){
    return(
      <div className="dropdown">
        <button 
          className="btn btn-primary dropdown-toggle"
          type="button"
          onClick={this.toggleShow}
          onBlur={this.hide}
        >

        {"Dropdown Example"}
          
        <span className="caret"></span>
        </button>
        {
          this.state.show &&
        (
          <ul className="dropdown-menu" style={{display: 'block'}}>
          <li><a onClick={this.doSomething} href="#">HTML</a></li>
          <li><a onClick={this.doSomething} href="#">CSS</a></li>
          <li><a onClick={this.doSomething} href="#">JavaScript</a></li>
        </ul>
        )
        }
      </div>
    );
  }
}


ReactDOM.render(<DropDown />, document.getElementById('root'));
Run Code Online (Sandbox Code Playgroud)
<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>

<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<div id="root"></div>
Run Code Online (Sandbox Code Playgroud)