反应-防止父母与子女之间的事件触发

我有这样一个场景,当单击父元素时,它会翻转来显示一个具有不同颜色的子元素。不幸的是,当用户点击其中一种颜色时,父颜色上的“点击”事件也会被触发。

当单击子项时,如何停止父项上的事件触发器?

我想知道可能的解决办法:

  1. CSS
    在单击子类时将 pointer-events : none类追加到父类。但是,这意味着以后需要清除 pointer-events类的父类。

  2. 使用 Ref
    记录父 React元素的 ref,然后单击子元素,比较 event.target和 ref?我不喜欢这个,因为我不喜欢全球 ref

我们将非常感谢各位的想法和更好的解决方案。问题是: 当单击子项时,如何停止父项上的事件触发器?

86437 次浏览

You can use stopPropagation

stopPropagation - Prevents further propagation of the current event in the bubbling phase

var App = React.createClass({
handleParentClick: function (e) {
console.log('parent');
},


handleChildClick: function (e) {
e.stopPropagation();
console.log('child');
},


render: function() {
return <div>
<p onClick={this.handleParentClick}>
<span onClick={this.handleChildClick}>Click</span>
</p>
</div>;
}
});


ReactDOM.render(<App />, 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>
<div id="root"></div>

I wanted to invoke function on props but at the same time wanted to stop event propagation from child to parent, here is how its handled

class LabelCancelable extends Component {


handleChildClick(e) {
e.stopPropagation()
}
closeClicked(e, props) {
e.stopPropagation();
props.onCloseClicked()
}


render() {
const {displayLabel} = this.props;
return (
<span className={ "label-wrapper d-inline-block pr-2 pl-2 mr-2 mb-2" } onClick={ this.handleChildClick }>
<button type="button" className="close cursor-pointer ml-2 float-right" aria-label="Close"
onClick={(e) => this.closeClicked(e, this.props) }>
<span aria-hidden="true">&times;</span>
</button>
<span className="label-text fs-12">
{ displayLabel }
</span>
</span>
);
}
}


export default LabelCancelable;

Another solution is to attach to the event callback on the parent the following:

if(event.target == event.currentTarget){
event.stopPropagation()
....
}

This way you can intercept events, that originated in the attached DOM node and unrelated events are relayed to the next node.

I had the same issue in React and solved it using the solution bellow:

if(e.currentTarget != e.target ) return;
.......

I had this problem with Material-UI DataGrid and solved it using this:

event.defaultMuiPrevented = true;

e.g:

<DataGrid
onCellDoubleClick={(params, event) => {
if (!event.ctrlKey) {
event.defaultMuiPrevented = true;
}
}}
{...data}
/>

I find this solution the cleanest. Thank you @JohnFash!

onClick={(event) => event.currentTarget == event.target && doSomething(event)}

Here is an attempt at explaining this in more details: when your mouse enters the parent element, the currentTarget is set (event), then when it enters the child element, the target changes. If you don't do the check, the parent's onClick triggers because the mouseleave event hasn't triggered.

Old question but had trouble then solved it myself I just stopped the event on the 'child' div like so this then passed down through children, so you can place where you want this to stop a click event;

<div onClick={doThisClickEvent}>
<div onClick={(e) => e.stopPropagation()}>
<div>
<p>This now wont trigger click event</p>
</div>
</div>
</div>