点击任意位置以关闭下拉列表

时间:2017-06-17 09:52:44

标签: javascript jquery reactjs ecmascript-6

我在页面上有多个自定义构建下拉组件。我使用setState

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

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

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

3 个答案:

答案 0 :(得分:12)

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

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

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

以下是一个示例,您可以看到它的演示here

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;

答案 1 :(得分:1)

您可以使用为您提取身体事件处理摘要的react-onclickoutside库。您只需将组件包装在onClickOutside更高阶的组件中,该组件将在下拉菜单之外的任何时候执行handleClickOutside回调。这样你就可以拥有一个私密的&#34; open&#34;在所有下拉菜单中陈述并且不关心如何实现处理。

代码可能如下所示:

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)

答案 2 :(得分:0)

首先,我们以open值为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>
   }
   }`