如何阻止父元素的事件传播到子元素

16
我想在我的HTML中阻止父级
向子级
传播事件。这是我尝试做的简单代码:
<div>
  <div id='categoryList'>
    <div class='listed-category'>
      <span>some content</span>
      <a id='close'>x</a> //"a" is used to remove the div
    </div>
  </div>
</div>
<div id='dropdown'>
</div>

如果我点击上面代码中的<div id='categoryList'>,那么下面的代码将使<div id='dropdown'>上下滑动。

$(document).ready(function () {

    $('#categoryList').click(function (event) {
        event.preventDefault();
        event.stopPropagation();
        if ($('#dropdown').is(":visible")) {
            $('#dropdown').slideUp(400);
        }
        else {
            $('#dropdown').slideDown(400);
        }
    });
})

但是当我点击子元素<div class='listed-category'>时,上面的JavaScript会执行,导致<div id='dropdown'>向上或向下滑动。如何停止这个操作?但我仍然想能够点击<a id='close'>来删除子元素div

7个回答

27

检查目标是否与点击的对象匹配。将此代码尝试放在点击事件处理程序的开头。

if( event.target !== this ) {
       return;
}
//...do stuff.. 

迄今为止最好的解决方案在这里 - 比那些有点不符合你要求的内置API更好。 - Andrew Bowman
3
我建议使用event.target !== event.currentTarget而不是this,因为this的上下文可能会被重新绑定。 - Ezio_
绝妙的解决方案。Ezio的建议也可行。 - Chrysotribax

6
你需要停止在子元素上进行事件传播,而不是在父元素上进行。因此你应该这样写:
 $('.listed-category').click(function(event){
    event.stopPropagation();
});

如果你想点击 a 标签并停止事件传播,你还需要编写以下代码:

 $('a#close').click(function(event){
    event.stopPropagation();
});

无论如何,我建议采用Yuriy的答案。我只想让你知道,如果你不想运行父级事件,应该在子元素中使用event.stopPropagation(),而不是在父级元素中使用。


1
如果有3-4个子元素,那么我们需要添加更多的事件处理程序吗? - iurii_n
@YuriyNedostup 是的,你的方法比我的好。我只是想让他知道应该把event.stopPropagation()放在子元素而不是父元素中。 - Elec

2
更加优雅的解决方案是使用CSS并在子元素上禁用指针事件。
#categoryList * {
    pointer-events: none;
}

如果您想要在 listed-category 元素上没有任何事件,可以按照以下步骤:

#listed-category {
    pointer-events: none;
}

1

http://codepen.io/rakeshcode/pen/KrZdNo

$(document).ready(function(){
  $(".arrow").click(function(){
  $(".row").slideToggle();
  
  });

$(".btn").click(function(event){
   event.stopPropagation();
  //$(".btn").attr("href","www.yahoo.com")
});
})
.btn {
  display: block;
  padding:15px;
  background-color:green;
  width:100px;
  margin-top:15px;
  text-decoration:none;
  margin-left:auto;
  margin-right:auto;
  
  
  
}
.arrow {
  cursor:pointer;
  text-align: center;
  padding:10px 0;
  font-size:15px;
  font-weight:bold;
  background-color:grey;
  margin-top:15px;
}
.container {
  max-width:600px;
  margin-left:auto;
  margin-right:auto; 
}
.close {
  height:75px;
  overflow:hidden;
  transition-duration: 0.3s;  
  transition-timing-function: cubic-bezier(0, 1, 0.5, 1);
}
.open {
  height:215px;
  overflow: hidden;
  transition-property:height;
  -moz-transition-duration: 0.3s;
    -webkit-transition-duration: 0.3s;
    -o-transition-duration: 0.3s;
    transition-duration: 0.3s;  
  transition-timing-function: ease-in;
}
.up {
  background-color:red; 
}
.down {
  background-color:green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
  <div class="arrow"> Click here Click here<a class="btn" href="www.google.com" target="_blank">click here</a></div>
  <div class="wrap">
  <div class="row">The most effective plac elearning,’ they most likely don’t know this themselves.Well, the most effective place to start is to dig into what the person asking for this training, ACTUALLY needs. Because if they’re dumping a huge stack of content on your desk and giving you vague instructions to ‘turn it into elearning,’ they most likely don’t know this themselves.Well, the most effective place to start is to dig into what the person asking for this training.ACTUALLY needs. Because if they’re dumping a huge stack of content on your desk and giving you vague instructions to ‘turn it into elearning,’ they most likely don’t know this themselves.Well, the most effective place to start is to dig into what the person asking for this trainingACTUALLY needs. Because if they’re dumping a huge stack of content on your desk and giving you vague instructions to ‘turn it into elearning,’ they most likely don’t know this themselves.Well, the most effective place to start is to dig into what the person asking for this training</div>
  </div>
  </div>


这是一个例子。 - Rakesh M

1

我建议您在

标签中使用unbind()方法,而不是使用e.stopPropagation。

$('.listed-category').unbind('click');

这将允许停止对 .listed-category div 的传播效应。方法 e.stopPropagation() 无法解决该问题,因为它只适用于父元素,而不是子元素。
您可以随时创建一个新函数并将其分配给 .listed-category div。您还可以查看此链接中的 unbind() 方法文档:http://api.jquery.com/unbind/ 希望这有所帮助!

1

接受的答案是正确的,但在最佳情况下,当您有多个嵌套元素时,您不希望取消事件,而是要获取实际点击的父容器并与其一起工作。

$('.clicked-container').click((e) => {
    let t = e.target;
    while (!$(t).hasClass( "clicked-container" )) { t = t.parentNode; }
     
    ...
    $(t).toggleClass('active-or-whatever-you-want');
});

同时,“this”在ES6中使用箭头(=>)时不再指向同一对象,需要显式绑定“this”。

请勿在HTML元素上尝试此操作;-) - Claudio Ferraro

0

使用React中的ref阻止事件冒泡的示例:

import React, { useRef } from "react";

const Modal = ({
  onClick,
}) => {
  const modalRef = useRef();

  return (
    <div
      ref={modalRef}
      onClick={(e) => {
        if (e.target !== modalRef.current) {
          return;
        }
        onClick();
      }}
    >
    </div>
  );
};

export default Modal;

参考资料

https://dev59.com/yF4c5IYBdhLWcg3wMnz1#28210173


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