【问题标题】:ReactJS Dropdown menu, close other menus before opening currentReactJS 下拉菜单,在打开当前菜单之前关闭其他菜单
【发布时间】:2019-02-06 17:53:17
【问题描述】:

我做了一些下拉菜单:

export default class DropdownMenu extends Component {

    constructor(props) {
        super(props)

        this.state = {
            menuOpen: false,
            highlight: false,
            count: this.props.count | 0
        }
        this.showDropdown = this.showDropdown.bind(this);
    }

    componentDidMount() {

    }

    showDropdown() {
            this.setState({
                menuOpen: !this.state.menuOpen
            });
    }

    render() {
        return <div className="dropdown__menu" onClick={this.showDropdown}>
            {this.props.text} {this.state.count > 0 ? <b>{this.state.count}</b> : ''}
            <div className="dropdown__content" style={this.state.menuOpen ? {'display': 'block'} : {'display': 'none'}}>
                {this.props.children}
            </div>
        </div>
    }
}

问题是您可以打开所有它们并让它们保持打开状态,直到您再次单击它们以关闭它们。如果打开了另一个菜单,我该如何关闭其他任何打开的菜单?


这里是它们的实现位置:

render() {
        ...
                <div className="filter_container">
                    <DropdownMenu text="New" count={127} disabled/>
                    <DropdownMenu text="Only show">
                        <li>New</li>
                        <li>Old</li>
                    </DropdownMenu>
                    <DropdownMenu text="Other">
                        <li>one</li>
                        <li>two</li>
                    </DropdownMenu>
                    <DropdownMenu text="Sort by">
                        <li>Name</li>
                        <li>Age</li>
                        <li>Value</li>
                    </DropdownMenu>
                </div>
            </div>
...

【问题讨论】:

  • 您是否运行地图来呈现 DropdownMenus 列表。您能显示该组件的代码吗?
  • @anuragb26 请查看我的编辑。
  • @imperium2335 你有机会看到解决方案吗?你觉得它们有用吗?

标签: javascript reactjs


【解决方案1】:

您可以使用onBlur,因为当另一个被点击时它会失去焦点。

class DropDown extends React.Component {
  state = {
    isVisible: false
  }
  
  closeMenu = () => {
    this.setState({ isVisible: false })
  }
  
  toggleMenu = () => {
    this.setState(prevState => ({ isVisible: !prevState.isVisible }))
  }
  
  render() {
    const { isVisible } = this.state;
    return (
      <div
        className="dropdown__menu"
        onBlur={this.closeMenu}
        tabIndex={0}
        role="menu"
        onClick={this.toggleMenu}>
        {isVisible ? 'visible' : 'hidden'}
      </div>
    )
  }
}


const App = () => (
  <div>
     <DropDown />
     <DropDown />
  </div>
)
 

ReactDOM.render(<App />, document.getElementById('root'));
.dropdown__menu {
  outline: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

【讨论】:

    【解决方案2】:

    因为 react 获得了一种数据流方式,你需要在父组件中执行此操作

    import React from 'react'
    
    class DropdownParent extends React.Component {
    
      state = {
        openedDropdown: null,
      };
    
      render() {
        return (
          <React.Fragment>
            <Dropdown
              name="dropdown1"
              isOpen={this.state.openedDropdown === 1}
              onClick={() => this.setState({ openedDropdown: 1 })}
              onClose={() => this.setState({ openedDropdown: null })}
            />
            <Dropdown
              name="dropdown2"
              isOpen={this.state.openedDropdown === 2}
              onClick={() => this.setState({ openedDropdown: 2 })}
              onClose={() => this.setState({ openedDropdown: null })}
            />
          </React.Fragment>
        )
      }
    }
    

    然后您需要 Dropdown 基于 props.isOpen,而不是您的 state.menuOpen 并使用 props.onClick / props.onClose 而不是 this.showDropdown

    或者,您可以基于鼠标(如 onMouseDown onMouseEnter...)或焦点(onFocus onBlur ) 事件,但这很难让移动设备友好,并且不能确保您“同时只有一个下拉菜单”。 更多信息:https://reactjs.org/docs/events.html

    【讨论】:

    • 是的!我正要写下类似的东西。
    【解决方案3】:

    由于打开不再是封装在下拉列表状态中的信息,我建议将此信息上移到父组件的状态。

    您现在应该将 Dropdowns 转换为无状态函数:

    const DropdownMenu = ({ menuOpen, count, text, showDropdown }) => ( //props deconstruction
        <div className="dropdown__menu" onClick={showDropdown}>
            {text} 
            {count && <b>{count}</b>} //If you do not want to show anything if a condition is falsy, use the inline if &&
            <div className="dropdown__content" style={{ 'display': menuOpen ? 'block' : 'none' }}> //You can put the ternary condition directly into the JSON
                {this.props.children}
            </div>
        </div>
    )
    

    您现在必须存储在您的父组件中打开了哪个下拉菜单:

    class Parent extends Component {
        state = {
            openedDropdown = null;
        }
    

    并向下拉列表发送回调函数:

    dropdownClicked = openedDropdown => ev => {
        this.setState({ openedDropdown })
    }
    
    <DropdownMenu text="New" count={127} disabled showDropdown={this.dropdownClicked('New')}  menuOpen={this.state.openedDropdown === 'New'}/>
    <DropdownMenu text="Only show" showDropdown={this.dropdownClicked('Only')}  menuOpen={this.state.openedDropdown === 'Only'}>
        <li>New</li>
        <li>Old</li>
    </DropdownMenu>
    <DropdownMenu text="Other" showDropdown={this.dropdownClicked('Other')}  menuOpen={this.state.openedDropdown === 'Other'}>
        <li>one</li>
        <li>two</li>
    </DropdownMenu>
    <DropdownMenu text="Sort by" showDropdown={this.dropdownClicked('Sort')}  menuOpen={this.state.openedDropdown === 'Sort'}>
        <li>Name</li>
        <li>Age</li>
        <li>Value</li>
    </DropdownMenu>
    

    【讨论】:

      【解决方案4】:

      我会为此使用 redux。 https://redux.js.org/

      此解决方案允许您管理整个应用的状态。 它可用于存储有关打开的下拉菜单的信息,并在必要时对其进行更改。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-11
        • 1970-01-01
        • 2018-10-18
        • 2018-09-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-11
        相关资源
        最近更新 更多