React - 防止子事件触发父事件

问题描述 投票:0回答:8

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

如何在单击子级时停止父级上的事件触发器?

我想知道可能的解决方案:

  1. CSS
    单击子级时,将

    pointer-events : none
    类附加到父级。但是,这意味着稍后需要清除父级中的
    pointer-events
    类。

  2. 使用参考
    记录父

    ref
    元素的
    React
    并单击子元素,将
    event.target
    与参考进行比较?我不喜欢这个,因为我不喜欢全局
    ref

想法和更好的解决方案将不胜感激。问题是: 单击子项时如何停止父项上的事件触发器?

javascript css reactjs events dom-events
8个回答
247
投票

您可以使用

stopPropagation

stopPropagation
- 防止当前事件进一步传播 冒泡阶段

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>


30
投票

我在 React 中遇到了同样的问题,并使用以下解决方案解决了它:

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

8
投票

另一种解决方案是将以下内容附加到父级上的事件回调:

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

通过这种方式,您可以拦截源自附加 DOM 节点的事件,并将不相关的事件中继到下一个节点。


3
投票

我想在 props 上调用函数,但同时想停止从子级到父级的事件传播,以下是其处理方式

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;

3
投票

我发现这个解决方案是最干净的。谢谢你JohnsonFashanu

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

这里尝试更详细地解释这一点: 当鼠标进入父元素时,currentTarget 被设置(事件),然后当鼠标进入子元素时,目标发生变化。如果不进行检查,则父级的 onClick 会触发,因为 mouseleave 事件尚未触发。


2
投票

我刚刚停止了“儿童”div 上的事件,然后将其传递给儿童。您可以将其放置在您希望停止点击事件的位置:

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



0
投票

我在使用 Material-UI DataGrid 时遇到了这个问题,并使用以下方法解决了它:

event.defaultMuiPrevented = true;

例如:

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

0
投票

就我而言,在 JSX 文件中:只需将

onClick={(e) => e.stopPropagation()
添加到标签中。它只影响孩子,而不影响父母。

<td>
  {!item.user_info_user ? null : (
    <a
      href={`${ENVIRONMENT.LINK_TO_PROFILE}${item.user_info_user?.domain_url}`}
      target="_blank"         
      rel="noreferrer"
      onClick={(e) => e.stopPropagation()}
    >
      {item.user_info_user?.domain_url}
    </a>
  )}
</td>
© www.soinside.com 2019 - 2024. All rights reserved.