我的反应应用程序中有一个菜单框,当我单击“显示菜单”按钮并显示菜单时,我会显示该菜单框。如果我在菜单外单击
,我想隐藏菜单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给出不同的节点
时,点击这些子组件会关闭我的菜单答案 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>