【问题标题】:Close react button dropdown menu on clicking or hovering outside of menu area在菜单区域外单击或悬停时关闭反应按钮下拉菜单
【发布时间】:2018-02-22 12:54:08
【问题描述】:

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

<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>

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

【问题讨论】:

    标签: javascript html css reactjs


    【解决方案1】:

    有几种方法可以做到这一点。实现此目的的最简单方法是让事件侦听器侦听单击事件或为下拉组件编写 onBlur 函数。

      componentWillMount() {
        document.body.addEventListener('click', this.handleClick);
      }
    
      componentWillUnmount() {
        document.body.removeEventListener('click', this.handleClick);
      }
    

    然后您必须将您的组件包装在侦听器组件中。

    这是工作中的 JS 小提琴。 https://jsfiddle.net/vamshikrishna144/zukcpfr2/

    【讨论】:

    • 如果您可以使用引导程序来获得相同的按钮和菜单,并且可以在点击外部时演示关闭菜单操作会更好
    • @LokeshAgrawal 但这不是问题的一部分 :) 你到底关心什么?
    【解决方案2】:

    不要在你的 React 中使用 jQuery 事件和 DOM 操作,你没有抓住重点。
    你有一个 state 使用它!

    在以下示例中,您可以看到我删除了所有 jquery.jsbootstrap.js 文件,只保留了 bootstrap.css
    我使用state 来显示/隐藏&lt;ul&gt; 列表(我已将其设置为display: block 以覆盖bootstrap.css 的默认display: none)。
    我设置了 2 个关于显示和隐藏 &lt;ul&gt; 的主要处理程序和 1 个用于每个项目的 onclick 的处理程序:

    1. toggleShow() - 在按钮的onBlur 附加的state 中切换show 属性。
    2. hide() - 当然通过状态隐藏&lt;ul&gt;(它做了一个 更多的事情我会解释)。
    3. doSomething() - 将在单击项目时触发。

    这个场景有一个很好的挑战,当我们隐藏&lt;ul&gt; 时,我们无法处理点击事件。

    但是为什么呢?

    因为我们并没有真正隐藏它,所以当state.show 为假时它不会被渲染。所以基本上有一种setState 的竞争条件会触发针对无法运行的doSomething 事件处理程序的处理程序的重新渲染。
    所以这里的挑战是确定触发按钮的onBlur 事件的活动元素是否是&lt;ul&gt; 内的项目。如果是,那么我们需要让项目触发它的onClick 事件,然后才设置状态并“隐藏”。
    我们在relatedTarget 的帮助下做到了这一点,它附在event 上。这是我们正在寻找的活动元素,如果我们有一个而不是null,那么我们触发它的点击事件(不管它是什么元素,顺便说一句,我们不关心),然后我们使用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'));
    <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>

    【讨论】:

    • onMouseLeave={this.hide} 添加到ul 以获得OP 要求的悬停效果。
    • @totbar 我需要稍微修改一下逻辑,如果您在鼠标移出时将其隐藏,则无法单击它。在 OP 旁边并不清楚鼠标应该如何以及在何处连接。但这当然是可行的。
    【解决方案3】:

    onBlur = {() => console.log("点击外部")}

    上述方法在下拉菜单外点击时触发。您可以更改状态等以显示或隐藏您的 div 或响应下拉列表

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-05
      • 2022-11-03
      • 2018-04-20
      相关资源
      最近更新 更多