单击下拉菜单后隐藏它

时间:2020-03-12 14:50:56

标签: javascript reactjs

我在React App中实现的下拉菜单出现问题。

该下拉列表基于以下文章:https://blog.campvanilla.com/reactjs-dropdown-menus-b6e06ae3a8fe

打开和关闭下拉菜单可以很好地处理下拉菜单,但是当我单击菜单中的按钮时,出现以下错误:

TypeError: Cannot read property 'contains' of null

我回到博客,发现其他人在评论中报告了相同的错误:

不错。但是仅最后一部分不起作用。 dropDownMenu保持为“空”

一种可能的解决方案是将current添加到以下代码行:

原始版本

if (!this.dropdownMenu.contains(event.target)) {

已修改:

if (!this.dropdownMenu.current.contains(event.target)) {

我在StackOverflow上找到了类似的答案,其中另一个用户的下拉菜单有问题:Cannot read property 'addEventListener' of null on menu,但我仍然无法弄清错误。

InnerHeader.jsx

import React, { Component } from 'react';
import {Link, withRouter} from 'react-router-dom'
import logo from '../images/logo.svg'
import Settings from '../lotties/Settings'

class InnerHeader extends Component {
  constructor() {
  super();
    
  this.state = {
    showMenu: false,
    fade: false
  };
  
  this.showMenu = this.showMenu.bind(this);
  this.closeMenu = this.closeMenu.bind(this);
}


showMenu(event) {
  event.preventDefault();
  
  this.setState({ showMenu: true }, () => {
    document.addEventListener('click', this.closeMenu);
  });
}

closeMenu(event) {
  if (!this.dropdownMenu.current.contains(event.target)) {
    
    this.setState({ showMenu: false }, () => {
      document.removeEventListener('click', this.closeMenu);
    });  
    
  }
}
 
handleLogout = () => {
    localStorage.removeItem('authToken');
    this.setState({
      currentUser: null
    })
    this.props.history.push("/")
  }

render() {
    return (
        <>
        <div id="inner-header">
          <div className="logo">
            <Link to="/dashboard"><img src={logo} height="50px" alt="site logo" /></Link>
          </div>
          <div>
        <button 
          className="menu-button"
          onClick={this.showMenu}>
          <Settings/>
        </button>
        <br />
        {
          this.state.showMenu
          ? (
            <div
            className="drop-down fade-in"
            ref={(element) => {
              this.dropdownMenu = element;
            }}
            >
                <div className="center-it-menu">
                <Link to="/account">  Account </Link>
                <br />
                <Link to="/integrations"> Integrations </Link>
                <br />
                <Link to="/tutorials"> Tutorials </Link>
                <br />
                <Link to="/support"> Support </Link>
                <br />
                <button id="menu-alert" onClick={this.handleLogout}> Logout </button>
                </div>
              </div>
            )
            : (
              null
              )
            }
      </div>
        </div>
      </>
    )
  }
}

export default withRouter(InnerHeader)

由于我仍在学习编程,因此我不想依靠库来完成此任务,也不想只是寻求解决方案。除了解决方案外,我想知道是什么原因导致的,以及如何解决该问题。由于它是您在Google上反应创建下拉菜单时显示的第一篇文章之一,因此,如果有人尝试实现此功能,我希望他们对此有一个很好的答案。

2 个答案:

答案 0 :(得分:1)

我必须说,在所描述的场景中根本不需要ref属性。要使菜单在外部单击时折叠起来,可以使用Element.closest()方法,该方法将遍历DOM树以在className="menu"个祖先中找到带有event.target的元素:

const { Component } = React,
      { render } = ReactDOM

class Card extends Component {
  constructor() {
    super();
    
    this.state = {
      showMenu: false,
    };
    
    this.showMenu = this.showMenu.bind(this);
    this.closeMenu = this.closeMenu.bind(this);
  }
  
  showMenu(event) {
    event.preventDefault();
    
    this.setState({ showMenu: true }, () => {
      document.addEventListener('click', this.closeMenu);
    });
  }
  
  closeMenu(event) {
    if (!event.target.closest('.menu')) {
      
      this.setState({ showMenu: false }, () => {
        document.removeEventListener('click', this.closeMenu);
      });  
      
    }
  }

  render() {
    return (
      <div>
        <button onClick={this.showMenu}>
          Show menu
        </button>
        
        {
          this.state.showMenu
            ? (
              <div
                className="menu"
              >
                <button> Menu item 1 </button>
                <button> Menu item 2 </button>
                <button> Menu item 3 </button>
              </div>
            )
            : (
              null
            )
        }
      </div>
    );
  }
}

render (<Card />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>

答案 1 :(得分:0)

这是因为当您不单击按钮时,此代码未执行且未启动 this.dropdownMenu ,因此它是未定义 。在这种情况下,您应该使用 onChange 事件并向其添加一个侦听器,然后在该函数中执行所需的任何操作。希望会对您有帮助。