当在下拉菜单组件之外单击时,我想关闭一个下拉菜单。
我怎么做?
Answers:
在元素我已经加入mousedown
和mouseup
这样的:
onMouseDown={this.props.onMouseDown} onMouseUp={this.props.onMouseUp}
然后在父母中,我这样做:
componentDidMount: function () {
window.addEventListener('mousedown', this.pageClick, false);
},
pageClick: function (e) {
if (this.mouseIsDownOnCalendar) {
return;
}
this.setState({
showCal: false
});
},
mouseDownHandler: function () {
this.mouseIsDownOnCalendar = true;
},
mouseUpHandler: function () {
this.mouseIsDownOnCalendar = false;
}
该showCal
是一个布尔值,当true
显示在我的情况下,日历和false
隐藏它。
preventDefault()
立即调用事件,否则将引发本机Android行为,而React的预处理会干扰这些行为。从那以后我写了npmjs.com/package/react-onclickoutside。
使用生命周期方法,可以向文档添加和删除事件侦听器。
React.createClass({
handleClick: function (e) {
if (this.getDOMNode().contains(e.target)) {
return;
}
},
componentWillMount: function () {
document.addEventListener('click', this.handleClick, false);
},
componentWillUnmount: function () {
document.removeEventListener('click', this.handleClick, false);
}
});
查看此组件的第48-54行:https : //github.com/i-like-robots/react-tube-tracker/blob/91dc0129a1f6077bef57ea4ad9a860be0c600e9d/app/component/tube-tracker.jsx#L48-54
查看事件的目标,如果事件直接在组件上或该组件的子组件上,则单击位于内部。否则它在外面。
React.createClass({
clickDocument: function(e) {
var component = React.findDOMNode(this.refs.component);
if (e.target == component || $(component).has(e.target).length) {
// Inside of the component.
} else {
// Outside of the component.
}
},
componentDidMount: function() {
$(document).bind('click', this.clickDocument);
},
componentWillUnmount: function() {
$(document).unbind('click', this.clickDocument);
},
render: function() {
return (
<div ref='component'>
...
</div>
)
}
});
如果要在许多组件中使用它,那么使用mixin会更好:
var ClickMixin = {
_clickDocument: function (e) {
var component = React.findDOMNode(this.refs.component);
if (e.target == component || $(component).has(e.target).length) {
this.clickInside(e);
} else {
this.clickOutside(e);
}
},
componentDidMount: function () {
$(document).bind('click', this._clickDocument);
},
componentWillUnmount: function () {
$(document).unbind('click', this._clickDocument);
},
}
在此处查看示例:https://jsfiddle.net/0Lshs7mg/1/
this.refs.component
指的DOM元素作为0.14的facebook.github.io/react/blog/2015/07/03/...
对于您的特定用例,当前接受的答案是经过精心设计的。如果您想在用户单击下拉列表时进行监听,只需将<select>
组件用作父元素并onBlur
为其添加处理程序即可。
这种方法的唯一缺点是,它假定用户已经保持对元素的关注,并且它依赖于表单控件(如果考虑到tab
键也可以使元素聚焦和模糊,那么它可能是您想要的,也可能不是您想要的)),但这些缺点实际上只是对更复杂的用例的限制,在这种情况下,可能需要更复杂的解决方案。
var Dropdown = React.createClass({
handleBlur: function(e) {
// do something when user clicks outside of this element
},
render: function() {
return (
<select onBlur={this.handleBlur}>
...
</select>
);
}
});
onBlur
div如果具有tabIndex
属性,也可与div一起使用
我已经为源自组件外部的事件React-outside-event编写了通用事件处理程序。
实现本身很简单:
window
对象。onOutsideEvent
在目标组件上触发。import React from 'react';
import ReactDOM from 'react-dom';
/**
* @param {ReactClass} Target The component that defines `onOutsideEvent` handler.
* @param {String[]} supportedEvents A list of valid DOM event names. Default: ['mousedown'].
* @return {ReactClass}
*/
export default (Target, supportedEvents = ['mousedown']) => {
return class ReactOutsideEvent extends React.Component {
componentDidMount = () => {
if (!this.refs.target.onOutsideEvent) {
throw new Error('Component does not defined "onOutsideEvent" method.');
}
supportedEvents.forEach((eventName) => {
window.addEventListener(eventName, this.handleEvent, false);
});
};
componentWillUnmount = () => {
supportedEvents.forEach((eventName) => {
window.removeEventListener(eventName, this.handleEvent, false);
});
};
handleEvent = (event) => {
let target,
targetElement,
isInside,
isOutside;
target = this.refs.target;
targetElement = ReactDOM.findDOMNode(target);
isInside = targetElement.contains(event.target) || targetElement === event.target;
isOutside = !isInside;
if (isOutside) {
target.onOutsideEvent(event);
}
};
render() {
return <Target ref='target' {... this.props} />;
}
}
};
要使用组件,需要使用高阶组件包装目标组件类声明,并定义要处理的事件:
import React from 'react';
import ReactDOM from 'react-dom';
import ReactOutsideEvent from 'react-outside-event';
class Player extends React.Component {
onOutsideEvent = (event) => {
if (event.type === 'mousedown') {
} else if (event.type === 'mouseup') {
}
}
render () {
return <div>Hello, World!</div>;
}
}
export default ReactOutsideEvent(Player, ['mousedown', 'mouseup']);
即使它对我没有用,我还是投票了一个答案。最终导致我找到了这个解决方案。我稍微改变了操作顺序。我在目标上监听mouseDown,在目标上监听mouseUp。如果其中任何一个返回TRUE,我们都不会关闭模式。一旦注册了单击,就可以在任何地方将这两个布尔值{mouseDownOnModal,mouseUpOnModal}设置回false。
componentDidMount() {
document.addEventListener('click', this._handlePageClick);
},
componentWillUnmount() {
document.removeEventListener('click', this._handlePageClick);
},
_handlePageClick(e) {
var wasDown = this.mouseDownOnModal;
var wasUp = this.mouseUpOnModal;
this.mouseDownOnModal = false;
this.mouseUpOnModal = false;
if (!wasDown && !wasUp)
this.close();
},
_handleMouseDown() {
this.mouseDownOnModal = true;
},
_handleMouseUp() {
this.mouseUpOnModal = true;
},
render() {
return (
<Modal onMouseDown={this._handleMouseDown} >
onMouseUp={this._handleMouseUp}
{/* other_content_here */}
</Modal>
);
}
这样做的好处是,所有代码都由子组件而不是父组件组成。这意味着在重复使用此组件时,无需复制任何样板代码。
.backdrop
)。.target
)放在.backdrop
元素之外,并具有更大的堆叠索引(z-index
)。然后,对.backdrop
元素的任何单击都将被视为“ .target
元素外部”。
.click-overlay {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 1;
}
.target {
position: relative;
z-index: 2;
}
您可以使用ref
s实现此目的,类似以下的内容应该起作用。
将添加ref
到您的元素:
<div ref={(element) => { this.myElement = element; }}></div>
然后,您可以添加一个函数来处理元素外部的点击,如下所示:
handleClickOutside(e) {
if (!this.myElement.contains(e)) {
this.setState({ myElementVisibility: false });
}
}
最后,添加和删除事件侦听器,将挂载和卸载。
componentWillMount() {
document.addEventListener('click', this.handleClickOutside, false); // assuming that you already did .bind(this) in constructor
}
componentWillUnmount() {
document.removeEventListener('click', this.handleClickOutside, false); // assuming that you already did .bind(this) in constructor
}
handleClickOutside
中document.addEventListener()
通过添加this
引用。否则,它将导致未捕获的ReferenceError:handleClickOutside未在componentWillMount()
派对晚了,但是我成功地在下拉菜单的父元素上设置了一个模糊事件,并使用关联的代码关闭了下拉菜单,并且还将mousedown侦听器附加到检查下拉菜单是否打开的父元素上是否打开,如果打开则将停止事件传播,从而不会触发模糊事件。
由于mousedown事件起泡,这将防止子项上的任何mousedown导致父项模糊。
/* Some react component */
...
showFoo = () => this.setState({ showFoo: true });
hideFoo = () => this.setState({ showFoo: false });
clicked = e => {
if (!this.state.showFoo) {
this.showFoo();
return;
}
e.preventDefault()
e.stopPropagation()
}
render() {
return (
<div
onFocus={this.showFoo}
onBlur={this.hideFoo}
onMouseDown={this.clicked}
>
{this.state.showFoo ? <FooComponent /> : null}
</div>
)
}
...
据我所知,e.preventDefault()不必被调用,但是无论出于何种原因,没有它,Firefox都无法正常播放。适用于Chrome,Firefox和Safari。
使用出色的react-onclickoutside混合功能:
npm install --save react-onclickoutside
然后
var Component = React.createClass({
mixins: [
require('react-onclickoutside')
],
handleClickOutside: function(evt) {
// ...handling code goes here...
}
});