드롭 다운 구성 요소 외부에서 클릭이 발생하면 드롭 다운 메뉴를 닫고 싶습니다.
어떻게하나요?
답변
추가 한 요소에서 다음 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
가죽 그것.
답변
수명주기 메서드를 사용하여 문서에 이벤트 리스너를 추가 및 제거합니다.
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/
답변
특정 사용 사례의 경우 현재 허용되는 답변은 약간의 과잉 엔지니어링입니다. 사용자가 드롭 다운 목록을 클릭 할 때 수신 대기하려면 <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>
);
}
});
답변
컴포넌트 외부에서 발생하는 이벤트에 대한 일반 이벤트 핸들러 인 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']);
답변
나는 그것이 나를 위해 작동하지 않았지만 대답 중 하나에 투표했습니다. 결국 저를이 솔루션으로 이끌었습니다. 작업 순서를 약간 변경했습니다. 나는 target에서 mouseDown을, target에서 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;
}
- 예 : http://jsfiddle.net/LHmwd/
- 토론에 대한 추가 정보 : https://github.com/facebook/react/issues/579