繁体   English   中英

单击任意位置以关闭下拉菜单反应

[英]click anywhere to close dropdown in react

我在页面上有多个反应的自定义构建下拉组件。 我使用 setState 触发列表项打开

toggleDropdown = (id) => {
        this.setState(prevState => ({
            [`dropdown${name}`]: !prevState[`dropdown${id}`] //dropdownA, dropdownB, dropdownC and so on
        }))
    }

如果在菜单打开时单击下拉菜单,这也将切换它。 但是后来我有更多的下拉列表,如果我打开一个下拉列表,其他下拉列表将不会关闭,如何解决这个问题? 我在 componentWillMount 中使用了一种“hacky”方式与 jquery 混合反应,在 body 上绑定单击事件,检查下拉项是否可见,如果是,则关闭它。

我的问题是,有没有更好的做法来避免使用 jquery?

我的建议是您使用合成事件onFocusonBlur来触发打开/关闭状态。 onFocus将在元素被点击时触发,而onBlur将在“非聚焦”(点击外部)时触发。 请参阅 文档

焦点/模糊还需要tabIndex属性/道具来处理非输入类型元素。

我可以建议查看react-select来源以及它们如何处理聚焦/模糊。

这是一个例子,你可以在这里看到它的演示

import React from "react";

class Dropdown extends React.Component {
  state = {
    open: false
  };

  toggleDropdown() {
    this.setState({ open: !this.state.open });
  }

  render() {
    return (
      <div
        style={{ border: "1px solid #CCC" }}
        onBlur={() => this.toggleDropdown()}
        onFocus={() => this.toggleDropdown()}
        tabIndex="0"
      >
        Dropdown
        {this.state.open && (
          <div>
            <div>Red</div>
            <div>Green</div>
            <div>Blue</div>
          </div>
        )}
      </div>
    );
  }
}

export default Dropdown;

您可以使用react-onclickoutside库为您抽象主体事件处理。 您只需要将您的组件包装在它们的onClickOutside高阶组件中,该组件将在单击发生在下拉菜单之外时执行handleClickOutside回调。 这样你就可以在所有下拉菜单中拥有一个私有的“打开”状态,而不用关心如何实现处理。

代码可能如下所示:

import React, { Component } from 'react'
import onClickOutside from 'react-onclickoutside'

class Dropdown extends Component {
    constructor() {
        this.state = {open: false}
    }

    // Method automatically executed by the library.
    handleClickOutside() {
        this.setState({open: false})
    }

    render() { ... }
}

export default onClickOutside(Dropdown)

首先,我们创建状态,打开值为 false,因此默认情况下关闭下拉列表。 然后,我们将为单击添加一个事件侦听器,该侦听器将关闭下拉列表并在关闭下拉列表后删除事件侦听器。 然后我们向按钮添加一个 onClick 事件,使用 toggleOpen() 将状态从 false 更改为 true。 然后我们将我们的内容包装在 if/or 中以检查内容是否打开:

`class Dropdown extends React.Component {

     constructor() {
         super();

         this.state = {
             open: false
         }
         this.toggleOpen = this.toggleOpen.bind(this);
         this.toggleClosed = this.toggleClosed.bind(this);
     }

    toggleOpen() {
        this.setState({ open: true }, () => {
            document.addEventListener('click', this.toggleClosed)
        })
    }

   toggleClosed() {
       this.setState({ open: false}, () => {
           document.removeEventListener('click', this.toggleClosed)
       })
   }

   render() {
       return(
           <div>
               <button onClick=({ this.toggleOpen })>
                   Dropdown
               </button>
               {
                    this.state.open
                    ? (
                          <span> Dropdown</span><br /><br />
                          <span> content</span><br /><br />
                      ) :
                      (
                          null
                      )
        </div>
   }
   }`

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM