反向冒泡:防止点击DOM子元素

3

我知道事件冒泡和event.stopPropagation()的工作原理,但是我正在寻找一种避免在DOM节点的所有子元素上使用点击处理程序的方法。

<div onclick="console.log('LOG ME')">
  <div onclick="console.log('DO NOT LOG ME')">Click me</div>
</div>

我希望记录“LOG ME”,但不记录“DO NOT LOG ME”。
我发现使用pointer-events:none的CSS方法可以解决问题,但是会使所有子div上的:hover和:focus CSS样式消失。
你有什么想法吗?
编辑:一些背景信息。我正在使用React。外部div是一个HOC,内部div是一个可见组件。我希望HOC捕获子组件的所有点击事件,并停止传播到子组件。在React中可以这样做:
const HOC = ChildComponent => class extends Component {
  handleClick = event => { /* Do what with event? */ }

  render() {
    return <div onClick={this.handleClick}>
      <ChildComponent />
    </div>;
  }
}

其中ChildComponent是一个可点击组件。


1
你需要内部监听器的使用案例是什么? - charlietfl
我正在使用React。外部div是一个高阶组件,内部div是可见组件。我希望高阶组件能够捕获子组件的所有点击事件。 - jeanpaul62
3个回答

4

更新(针对更新的问题)

如果您正在使用React,请在事件末尾使用Capture,以便处理程序在捕获阶段触发。 (请参见https://reactjs.org/docs/events.html#supported-events

因此,可以这样做:

const HOC = ChildComponent => class extends Component {
  handleClick = event => { 
     /* Do what with event? */
     event.stopPropagation();
     /*the rest of the code you want for handling the click*/
  }

  render() {
    return <div onClickCapture={this.handleClick}>
      <ChildComponent />
    </div>;
  }
}

您需要停止事件的传播,并且需要使用事件的捕获阶段,而不是冒泡阶段。

因此,不要使用onclick, 而是使用正确的方法附加事件处理程序。对于您想要成为容器的外部事件,请使用true作为第三个参数(useCapture参数)。

document.querySelector('.outer').addEventListener('click', function(e){
  e.stopPropagation();
  console.log('LOG ME')
}, true);

document.querySelector('.inner').addEventListener('click', function(e){
  console.log('DO NOT LOG ME')
}, false);
<div class="outer">
  <div class="inner">Click me</div>
</div>


刚刚意识到我的问题更具体了。我编辑了原始问题,并添加了“React”标签。 - jeanpaul62
1
@amaurymartiny 更新了答案。基本上使用 onClickCapture 替代 onClick,并使用 event.stopPropagation() - Gabriele Petrioli

0
你可以使用事件的捕获阶段来钩入父元素的点击事件,并停止传播到子元素。
你还应该遵循现代事件注册标准不使用内联HTML事件属性

// Normally, the following would set up event handler that bubbles up through all div elements
// but, you will see that it only fires once, for the parent element...
document.querySelector("div").addEventListener("click", function(evt){
  
    console.log(this);
    evt.stopPropagation();  // Don't allow the event
    
  }, true); // Adding the 3rd argument of true causes the event handler to be registered during the capture phase
<div class="parent">
  <div class="child">Click me</div>
</div>


刚刚意识到我的问题更具体了。我编辑了原始问题,并添加了“React”标签。 - jeanpaul62

0

这可能与您的情况有关,但是以嵌套内联onclick的示例为例,您可以删除嵌套的onclick属性,事件处理程序将不会被调用

[].slice.call(document.querySelectorAll('[onclick] [onclick]')).forEach(function(el) {
    el.removeAttribute('onclick')
})
<div onclick="console.log('LOG ME')">
  <div onclick="console.log('DO NOT LOG ME')">Click me</div>
</div>


不适用于我的情况。我编辑了原始问题。 - jeanpaul62

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接