In my react application one of the component is creating a button dropdown menu like below.
在我的react应用程序中,一个组件正在创建一个按钮下拉菜单,如下所示。
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Dropdown Example
<span class="caret"></span></button>
<ul class="dropdown-menu">
<li><a onClick=doSomething href="#">HTML</a></li>
<li><a onClick=doSomething href="#">CSS</a></li>
<li><a onClick=doSomething href="#">JavaScript</a></li>
</ul>
</div>
How can I close this menu if someone clicks/hovers anywhere outside of this menu area?
如果有人在这个菜单区域之外的任何地方点击/停留,我如何关闭这个菜单?
2 个解决方案
#1
4
Don't use jQuery events and DOM manipulations inside your React, you are missing the point.
You have a state
use it!
不要在您的response中使用jQuery事件和DOM操作,您没有抓住要点。你有一个州在使用它!
In the following example you can see i removed all jquery.js
and bootstrap.js
files and kept only the bootstrap.css
.
I use the state
in order to show / hide the <ul>
list (i've set it to display: block
in order to override the default display: none
of bootstrap.css
).
I have set 2 main handlers regarding showing and hiding the <ul>
and 1 handler for the onclick
of each item:
在下面的示例中,您可以看到我删除了所有jquery。js和引导。并只保留bootstrap.css文件。我使用状态来显示/隐藏
-
列表(我将它设置为display: block以覆盖默认显示:没有bootstrap.css)。关于显示和隐藏
-
和每个项目onclick的1个处理程序,我设置了2个主要处理程序:
-
toggleShow()
- Toggle theshow
property in thestate
attached to theonBlur
of the button. - 切换控件()——切换按钮onBlur的状态中的show属性。
-
hide()
- Hides the<ul>
via the state of course (it does one more thing which i will explain). -
隐藏()-通过状态隐藏
-
(它做了一件我将会解释的事情)。
-
doSomething()
- Will fire on click of an item. - doSomething() -将在单击一个项目时触发。
This scenario has a nice challenge though, when we hide the <ul>
we can't handle the click event.
这个场景有一个很好的挑战,当我们隐藏
-
时,我们无法处理单击事件。
But why?
但是为什么呢?
Because we don't really hide it, it doesn't get rendered when state.show
is false. So basically there's kind of a race condition of the setState
the triggers a re-render against the handler of the doSomething
event handler which can't run.
So the challenge here is to determine if active element that triggered the onBlur
event of the button is the item inside the <ul>
. If it is, then we need to let the item trigger it's onClick
event and only then set the state and "hide" the .
We did that with the help of relatedTarget
that attached to the event
. This is the active element that we are looking for, and if we have one and it's not null
then we trigger it's click event (no matter what element it is by the way as we don't care), and only then we set the state with show: false
.
因为我们没有隐藏它,它不会在状态时被渲染。显示是错误的。因此,基本上有一种setState的竞态条件触发对doSomething事件处理程序的处理程序的重新呈现,它不能运行。因此,这里的挑战是确定触发按钮的onBlur事件的活动元素是否是
-
中的项目。如果是,那么我们需要让项目触发它的onClick事件,然后设置状态并“隐藏”。我们是在事件相关目标的帮助下完成的。这是我们要寻找的活动元素,如果我们有一个,而且它不是null,那么我们就触发它的click事件(不管它是什么元素,顺便说一下,我们不关心),然后我们用show: false设置状态。
A working example:
一个工作示例:
class DropDown extends React.Component{
constructor(props){
super(props);
this.state = {
show: false
}
this.doSomething = this.doSomething.bind(this);
this.toggleShow = this.toggleShow.bind(this);
this.hide = this.hide.bind(this);
}
doSomething(e){
e.preventDefault();
console.log(e.target.innerHTML);
}
toggleShow(){
this.setState({show: !this.state.show});
}
hide(e){
if(e && e.relatedTarget){
e.relatedTarget.click();
}
this.setState({show: false});
}
render(){
return(
<div className="dropdown">
<button
className="btn btn-primary dropdown-toggle"
type="button"
onClick={this.toggleShow}
onBlur={this.hide}
>
{"Dropdown Example"}
<span className="caret"></span>
</button>
{
this.state.show &&
(
<ul className="dropdown-menu" style={{display: 'block'}}>
<li><a onClick={this.doSomething} href="#">HTML</a></li>
<li><a onClick={this.doSomething} href="#">CSS</a></li>
<li><a onClick={this.doSomething} href="#">JavaScript</a></li>
</ul>
)
}
</div>
);
}
}
ReactDOM.render(<DropDown />, document.getElementById('root'));
<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>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<div id="root"></div>
#2
2
There are several ways to do this. The easiest way you can achieve this is by either having event listeners to listen to the click events or write an onBlur function for the dropdown component.
有几种方法可以做到这一点。实现这一点的最简单方法是让事件监听器侦听单击事件,或者为下拉组件编写onBlur函数。
componentWillMount() {
document.body.addEventListener('click', this.handleClick);
}
componentWillUnmount() {
document.body.removeEventListener('click', this.handleClick);
}
And then you'll have to wrap your component inside the listener component.
然后你需要将你的组件封装到监听器组件中。
Here is the working JS fiddle. https://jsfiddle.net/vamshikrishna144/zukcpfr2/
这是工作的JS提琴。https://jsfiddle.net/vamshikrishna144/zukcpfr2/
#1
4
Don't use jQuery events and DOM manipulations inside your React, you are missing the point.
You have a state
use it!
不要在您的response中使用jQuery事件和DOM操作,您没有抓住要点。你有一个州在使用它!
In the following example you can see i removed all jquery.js
and bootstrap.js
files and kept only the bootstrap.css
.
I use the state
in order to show / hide the <ul>
list (i've set it to display: block
in order to override the default display: none
of bootstrap.css
).
I have set 2 main handlers regarding showing and hiding the <ul>
and 1 handler for the onclick
of each item:
在下面的示例中,您可以看到我删除了所有jquery。js和引导。并只保留bootstrap.css文件。我使用状态来显示/隐藏
-
列表(我将它设置为display: block以覆盖默认显示:没有bootstrap.css)。关于显示和隐藏
-
和每个项目onclick的1个处理程序,我设置了2个主要处理程序:
-
toggleShow()
- Toggle theshow
property in thestate
attached to theonBlur
of the button. - 切换控件()——切换按钮onBlur的状态中的show属性。
-
hide()
- Hides the<ul>
via the state of course (it does one more thing which i will explain). -
隐藏()-通过状态隐藏
-
(它做了一件我将会解释的事情)。
-
doSomething()
- Will fire on click of an item. - doSomething() -将在单击一个项目时触发。
This scenario has a nice challenge though, when we hide the <ul>
we can't handle the click event.
这个场景有一个很好的挑战,当我们隐藏
-
时,我们无法处理单击事件。
But why?
但是为什么呢?
Because we don't really hide it, it doesn't get rendered when state.show
is false. So basically there's kind of a race condition of the setState
the triggers a re-render against the handler of the doSomething
event handler which can't run.
So the challenge here is to determine if active element that triggered the onBlur
event of the button is the item inside the <ul>
. If it is, then we need to let the item trigger it's onClick
event and only then set the state and "hide" the .
We did that with the help of relatedTarget
that attached to the event
. This is the active element that we are looking for, and if we have one and it's not null
then we trigger it's click event (no matter what element it is by the way as we don't care), and only then we set the state with show: false
.
因为我们没有隐藏它,它不会在状态时被渲染。显示是错误的。因此,基本上有一种setState的竞态条件触发对doSomething事件处理程序的处理程序的重新呈现,它不能运行。因此,这里的挑战是确定触发按钮的onBlur事件的活动元素是否是
-
中的项目。如果是,那么我们需要让项目触发它的onClick事件,然后设置状态并“隐藏”。我们是在事件相关目标的帮助下完成的。这是我们要寻找的活动元素,如果我们有一个,而且它不是null,那么我们就触发它的click事件(不管它是什么元素,顺便说一下,我们不关心),然后我们用show: false设置状态。
A working example:
一个工作示例:
class DropDown extends React.Component{
constructor(props){
super(props);
this.state = {
show: false
}
this.doSomething = this.doSomething.bind(this);
this.toggleShow = this.toggleShow.bind(this);
this.hide = this.hide.bind(this);
}
doSomething(e){
e.preventDefault();
console.log(e.target.innerHTML);
}
toggleShow(){
this.setState({show: !this.state.show});
}
hide(e){
if(e && e.relatedTarget){
e.relatedTarget.click();
}
this.setState({show: false});
}
render(){
return(
<div className="dropdown">
<button
className="btn btn-primary dropdown-toggle"
type="button"
onClick={this.toggleShow}
onBlur={this.hide}
>
{"Dropdown Example"}
<span className="caret"></span>
</button>
{
this.state.show &&
(
<ul className="dropdown-menu" style={{display: 'block'}}>
<li><a onClick={this.doSomething} href="#">HTML</a></li>
<li><a onClick={this.doSomething} href="#">CSS</a></li>
<li><a onClick={this.doSomething} href="#">JavaScript</a></li>
</ul>
)
}
</div>
);
}
}
ReactDOM.render(<DropDown />, document.getElementById('root'));
<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>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<div id="root"></div>
#2
2
There are several ways to do this. The easiest way you can achieve this is by either having event listeners to listen to the click events or write an onBlur function for the dropdown component.
有几种方法可以做到这一点。实现这一点的最简单方法是让事件监听器侦听单击事件,或者为下拉组件编写onBlur函数。
componentWillMount() {
document.body.addEventListener('click', this.handleClick);
}
componentWillUnmount() {
document.body.removeEventListener('click', this.handleClick);
}
And then you'll have to wrap your component inside the listener component.
然后你需要将你的组件封装到监听器组件中。
Here is the working JS fiddle. https://jsfiddle.net/vamshikrishna144/zukcpfr2/
这是工作的JS提琴。https://jsfiddle.net/vamshikrishna144/zukcpfr2/