event.target分别对反应子组件进行处理

时间:2017-11-09 19:45:58

标签: javascript reactjs

我的反应应用程序中有一个菜单框,当我单击“显示菜单”按钮并显示菜单时,我会显示该菜单框。如果我在菜单外单击

,我想隐藏菜单
class MenuButton extends Component {
 constructor (props) {
  super (props)
  this.state = {showMenu: false}
  this.toggleMenu = this.toggleMenu.bind(this)
 }

 toggleMenu () {
   let showMenu = !this.state.showMenu
   this.setState({showMenu})
 }

 componentDidMount () {
  window.addEventListner('click', e => {
   if (e.target !== document.getElementById('menu-div') {
    this.setState({showMenu: false})
   }
  })
 }

 render () {} {
  return (
   <div>
    <button onClick={this.toggleMenu}>Menu</button>
    {this.state.showMenu ? <div id='menu-div><Menu /></div> : null}
   </div>
  )
 }
}

我的菜单组件有很多子组件

const Menu = () => {
  return (
    <div>
      <Component1/>
      <Component2/>
      <Component3/>
    </div>
  )
}

但是,当event.target给出不同的节点

时,点击这些子组件会关闭我的菜单

1 个答案:

答案 0 :(得分:3)

我不会在getElementById中使用DOM或搜索元素。这不是做事的“反应方式”,这被认为是一种不好的做法 而是使用refs API that react provides并获取对节点的引用 您可以添加mousedown的事件监听器并检查ref是否包含目标,如果不是,则表示您位于ref(您的情况下的菜单)之外。所以剩下的就是将状态设置为关闭它。

以下是我提到的实施代码的运行摘录:

class MenuButton extends React.Component {
  constructor(props) {
    super(props);
    this.state = { showMenu: false };
  }

  componentDidMount() {
    document.addEventListener("mousedown", this.handleOutsideClick);
  }

  componentWillUnmount() {
    document.removeEventListener("mousedown", this.handleOutsideClick);
  }

  toggleMenu = () => {
    let showMenu = !this.state.showMenu;
    this.setState({ showMenu });
  };

  handleOutsideClick = event => {
    if (this.menuRef && !this.menuRef.contains(event.target)) {
      this.setState({ showMenu: false });
    }
  };

  setRef = ref => {
    this.menuRef = ref;
  };

  render() {
    const { showMenu } = this.state;
    return (
      <div>
        <button onClick={this.toggleMenu}>Menu</button>
        {<Menu className={`${!showMenu && "hide"}`} setRef={this.setRef} />}
      </div>
    );
  }
}

class Menu extends React.Component {
  render() {
    const { setRef, className } = this.props;
    return (
      <div className={`menu ${className}`} ref={setRef}>
        <div>comp 1</div>
        <div>comp 2</div>
        <div>comp 3</div>
      </div>
    );
  }
}

ReactDOM.render(<MenuButton />, document.getElementById("root"));
.hide{
  display: none;
}

.menu{
  border: 1px solid #333;
  padding: 5px;
  max-width: 60px;
}
<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>
<div id="root"></div>