Я пытаюсь использовать event.stopPropagation() в компоненте ReactJS, чтобы остановить событие click от пузырьков и запустить событие click, которое было прикреплено JQuery в устаревшем коде, но похоже, что React stopPropagation() останавливается распространение на события, также связанные с React, и JQuery stopPropagation() не останавливает распространение событий, связанных с React.
Есть ли способ сделать stopPropagation() работать с этими событиями? Я написал простой JSFiddle, чтобы продемонстрировать это поведение:
/** @jsx React.DOM */
var Propagation = React.createClass({
alert: function(){
alert('React Alert');
},
stopPropagation: function(e){
e.stopPropagation();
},
render: function(){
return (
<div>
<div onClick={this.alert}>
<a href="#" onClick={this.stopPropagation}>React Stop Propagation on React Event</a>
</div>
<div className="alert">
<a href="#" onClick={this.stopPropagation}>React Stop Propagation on JQuery Event</a>
</div>
<div onClick={this.alert}>
<a href="#" className="stop-propagation">JQuery Stop Propagation on React Event</a>
</div>
<div className="alert">
<a href="#" className="stop-propagation">JQuery Stop Propagation on JQuery Event</a>
</div>
</div>
);
}
});
React.renderComponent(<Propagation />, document.body);
$(function(){
$(document).on('click', '.alert', function(e){
alert('Jquery Alert');
});
$(document).on('click', '.stop-propagation', function(e){
e.stopPropagation();
});
});
React использует событие делегирования с одним прослушивателем событий в document
для событий, которые пузырятся, например, 'click' в этом примере, что означает, что прекращение распространения невозможно; реальное событие уже распространилось к тому моменту, когда вы взаимодействуете с ним в React. stopPropagation
on Реакция синтетического события возможна, потому что React обрабатывает распространение синтетических событий внутри.
Используйте Event.stopImmediatePropagation
, чтобы ваш другой (jQuery в данном случае) прослушиватель не вызывал. Он поддерживается в IE9 + и современных браузерах.
stopPropagation: function(e){
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation();
},
В вашем коде jQuery также используется делегирование событий, что означает, что вызов stopPropagation
в обработчике не останавливает ничего; событие уже распространилось на document
, и будет запущен прослушиватель React.
// Listener bound to `document`, event delegation
$(document).on('click', '.stop-propagation', function(e){
e.stopPropagation();
});
Чтобы предотвратить распространение за пределами элемента, слушатель должен быть привязан к самому элементу:
// Listener bound to `.stop-propagation`, no delegation
$('.stop-propagation').on('click', function(e){
e.stopPropagation();
});
Изменить (2016/01/14): Уточнено, что эта делегация обязательно используется только для событий, которые пузырятся. Для получения дополнительной информации об обработке событий, источник React имеет описательные комментарии: https://github.com/facebook/react/blob/3b96650e39ddda5ba49245713ef16dbc52d25e9e/src/renderers/dom/client/ReactBrowserEventEmitter.js#L23
document
или корневой компонент React? На связанной странице просто написано «на верхнем уровне», что, как я понимаю, означает, что это не document
(но я не могу понять, насколько это актуально).
Мне удалось решить эту проблему, добавив следующее к моему компоненту:
componentDidMount() {
ReactDOM.findDOMNode(this).addEventListener('click', (event) => {
event.stopPropagation();
}, false);
}
Я столкнулся с этой проблемой вчера, поэтому я создал решение, совместимое с реакцией.
Отъезд react-native-listener. До сих пор он работал очень хорошо. Обратная связь оценена.
findDomNode
react-native-listener
использует findDomNode
который будет устаревшим github.com/yannickcr/eslint-plugin-react/issues/…
Это еще один интересный момент:
ev.preventDefault()
ev.stopPropagation();
ev.nativeEvent.stopImmediatePropagation();
Используйте эту конструкцию, если ваша функция обернута тегом
event.nativeEvent
- правильный ответ; Я был в состоянии использовать composedPath()
путем его: event.nativeEvent.composedPath()
Обновление: теперь вы можете <Elem onClick={ proxy => proxy.stopPropagation() } />
event.nativeEvent.stopImmediatePropagation
чтобы запретитьevent.nativeEvent.stopImmediatePropagation
других прослушивателей событий, но порядок выполнения не гарантируется.stopImmediatePropagation
утверждает, что прослушиватели событий будут вызываться в том порядке, в котором они были связаны. Если ваш React JS инициализируется до вашего jQuery (как в вашей скрипке), остановка немедленного распространения будет работать.