javascript 在 reactjs 中切换下拉菜单
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30135351/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Toggle dropdown menu in reactjs
提问by user2442241
I have the following code for a simple dropdown menu on my navbar: https://jsfiddle.net/jL3yyk98/10/
我的导航栏上有一个简单的下拉菜单的以下代码:https: //jsfiddle.net/jL3yyk98/10/
index.html
索引.html
<div id="menu-button"></div>
NavMenu.js
导航菜单.js
var NavMenu = React.createClass({
getDefaultProps: function()
{
return {
isOpen: false
};
},
render: function()
{
if (this.props.isOpen)
{
return (
<div className="dropdown">
<ul>
<li><a href="#">News</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Guidelines</a></li>
<li><a href="#">Exchange</a></li>
<li><a href="#">Forum</a></li>
</ul>
</div>
);
}
return null;
}
});
NavMenuButton.js
导航菜单按钮.js
var NavMenuButton = React.createClass({
getInitialState: function()
{
return {
isOpen: false
};
},
toggleMenu: function(e)
{
e.stopPropagation();
this.setState({isOpen: !this.state.isOpen});
},
onClose: function()
{
this.setState({isOpen: false});
},
componentDidMount: function ()
{
document.body.addEventListener('click', this.onClose);
},
componentWillUnmount: function ()
{
document.body.removeEventListener('click', this.onClose);
},
render: function()
{
return (
<div>
<a onClick={this.toggleMenu} href="#">Menu</a>
<NavMenu isOpen={this.state.isOpen} />
</div>
);
}
});
React.render(<NavMenuButton />, document.getElementById('menu-button'));
I understand with my current code that both the toggleMenu method and onClose method are called when the user clicks the menu button to close the menu (since they are also effectively clicking the body); and that the onClose method is called first, meaning that the state is set to false, but then the toggleMenu method is called and it's set back to true. Why is this, and how can I fix it so that clicking the menu button toggles the menu andclicking the body hides the menu?
我用我当前的代码理解,当用户单击菜单按钮关闭菜单时,toggleMenu 方法和 onClose 方法都会被调用(因为它们也有效地单击了正文);并且首先调用 onClose 方法,这意味着状态设置为 false,然后调用 toggleMenu 方法并将其设置回 true。为什么会这样,我该如何修复它以便单击菜单按钮切换菜单并单击正文隐藏菜单?
If this approach seems wrong what approach should I be using? I'm fairly new to react so I'm still learning what goes where and why.
如果这种方法看起来不对,我应该使用什么方法?我对反应还很陌生,所以我仍在学习什么去哪里以及为什么。
Also, I cannot use a full body div as the solution to this, it needs to be a typical dropdown; so if users want to interact with another part of the page (maybe clicking a link), then they can do that.
另外,我不能使用全身 div 作为解决方案,它需要是一个典型的下拉列表;因此,如果用户想要与页面的其他部分进行交互(可能单击链接),那么他们可以这样做。
回答by Jeremy D
Your issue is that clicking on the link will also call the body click listener. It means that your state will go from:
您的问题是点击链接也会调用正文点击侦听器。这意味着您的状态将从:
- Click on link
- Click listener on body called
- This.state.open set to false
- Render called with this.state.open false
- Click listener on the link called
- This.state.open set to true
- Render called with this.state.open true
- 点击链接
- 单击名为的主体上的侦听器
- this.state.open 设置为 false
- 使用 this.state.open false 调用渲染
- 单击名为的链接上的侦听器
- this.state.open 设置为 true
- 渲染调用 this.state.open true
e.stopPropagation() doesn't work in React. One workaround would be to:
e.stopPropagation() 在 React 中不起作用。一种解决方法是:
handleBodyClick: function(e)
{
if (e.target.nodeName !== 'A') {
this.setState({isOpen: false});
}
},
Another way (and better way) would be to have the click listener not on body, but on a div, and make it as big as possible (to be as the same size a body basically).
另一种方式(更好的方式)是让点击监听器不在身体上,而是在一个 div 上,并使其尽可能大(基本上与身体的大小相同)。
Here is an example with binding a click on a div instead of body: https://jsfiddle.net/jL3yyk98/
这是一个在 div 上绑定点击而不是 body 的示例:https: //jsfiddle.net/jL3yyk98/
回答by CooCoo
handleClose: function() {
this.setState({isOpen: false});
},
handleGlobalClick: function(event) {
var _con = this.refs.mC.getDOMNode() // <component ref="mC">
if (!(_con == event.target) && !_con.contains(event.target)) {
this.handleClose();
}
},
componentDidMount: function() {
document.body.addEventListener('click', this.handleGlobalClick);
},
componentWillUnmount: function() {
document.body.removeEventListener('click', this.handleGlobalClick);
},
this work on the latest chrome, you can also use the jQuery rewrite the node.contains()
这项工作在最新的 chrome 上,您也可以使用 jQuery 重写 node.contains()