Я хочу закрыть раскрывающееся меню, когда щелчок происходит за пределами раскрывающегося компонента.
Как я могу это сделать?
В элементе, который я добавил 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> ) } });
Если это будет использоваться во многих компонентах, лучше использовать миксин:
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 также работает с div, если у него естьtabIndex
атрибутЯ написал универсальный обработчик событий для событий, которые происходят вне компонента, response-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
ссылки. В противном случае выдает ошибку Uncaught 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.
источник
Я нашел более простой способ.
Вам просто нужно добавить
onHide(this.closeFunction)
модальный<Modal onHide={this.closeFunction}> ... </Modal>
Предполагая, что у вас есть функция для закрытия модального окна.
источник
Используйте отличный миксин react-onclickoutside :
А потом
var Component = React.createClass({ mixins: [ require('react-onclickoutside') ], handleClickOutside: function(evt) { // ...handling code goes here... } });
источник