jQuery:点击函数排除子元素。

155

尝试理解jQuery中的“.not()”函数,但遇到了问题。我想让父div可以被“点击”,但是如果用户点击子元素,脚本不会执行。

$(this).not(children()).click(function(){
   $(".example").fadeOut("fast");
});

HTML内容:

<div class="example">
   <div>
      <p>This content is not affected by clicks.</p>
   </div>
</div>
6个回答

214

要做到这一点,使用 .stopPropagation 停止子元素的点击事件:

$(".example").click(function(){
  $(this).fadeOut("fast");
}).children().click(function(e) {
  return false;
});

这将停止子元素点击事件冒泡到它们的父级,从而使父级无法接收到该点击事件。

.not() 用法略有不同,它可以过滤你所选的元素,例如:

<div class="bob" id="myID"></div>
<div class="bob"></div>

$(".bob").not("#myID"); //removes the element with myID
点击方面,你的问题在于单击子元素会向父元素冒泡,而不是你无意中将点击处理程序附加到子元素上。

当我将其他事件绑定到元素时,这会导致问题(子元素的onsubmit不再起作用,原因不明)。 - Asaf
19
针对这种情况,请使用e.stopPropagation();而不是return false; - Nick Craver
2
你也可以使用 }).find('.classes-to-ignore').click(function(e) { 来选择特定的子元素。 - Paul Mason
6
为什么你告诉他使用 e.stopPropagation(),然后又使用 return false 呢?return false 等同于 e.preventDefault(); e.stopPropagation(),可能会产生意外的副作用。 - Steen Schütt
@NickCraver 如果我想反过来怎么办?比如说 <div id="dropdown-menu"> <button> 点我</button></div> 如果我在 #dropdown-menu 上使用 stopPropagation(),那么 "点我" 按钮就会失效。如何避免它变得无效?通常可以使用 $(document).on('click','dropdown-menu',function(){e.stopPropgation();}); 来解决。但是当动态加载时,情况就非常严重了。这个解决方案不再起作用!我该怎么办?请看我的问题 - edam
显示剩余5条评论

194

我正在使用以下标记,并遇到了同样的问题:

<ul class="nav">
    <li><a href="abc.html">abc</a></li>
    <li><a href="def.html">def</a></li>
</ul>

这里我使用了以下逻辑:

$(".nav > li").click(function(e){
    if(e.target != this) return; // only continue if the target itself has been clicked
    // this section only processes if the .nav > li itself is clicked.
    alert("you clicked .nav > li, but not it's children");
});

就确切的问题而言,我认为以下方案可行:

$(".example").click(function(e){
   if(e.target != this) return; // only continue if the target itself has been clicked
   $(".example").fadeOut("fast");
});

或者当然也可以反过来:

$(".example").click(function(e){
   if(e.target == this){ // only if the target itself has been clicked
       $(".example").fadeOut("fast");
   }
});

28
我认为这是更好的解决方案。它不会以任何方式干扰孩子们,而且如果有成千上万的孩子,它应该表现得更好,因为它不会潜在地注册成千上万次回调函数。 - LucasB
4
еңЁжңҖиҝ‘зүҲжң¬зҡ„jQueryдёӯпјҢеә”иҜҘдҪҝз”Ё.on("click", ...)иҖҢдёҚжҳҜ.live()пјҢеӣ дёәиҮӘv1.7д»ҘжқҘе·Із»ҸеәҹејғдәҶ.live()гҖӮиҜ·еҸӮи§Ғhttp://api.jquery.com/live/гҖӮ - Chris
是的,@Chris我在2012年11月16日10:12发布了。 - l2aelba
抱歉,可能不需要引用您的ID。我添加了这个注释主要是为了其他阅读此答案的人。 - Chris
2
这个答案比被采纳的答案更好,因为它不会中断子元素上的任何点击事件。 - cameronjonesweb
这不是被接受的答案,但它是正确的答案。 - Richie

26

或者您也可以这样做:

$('.example').on('click', function(e) { 
   if( e.target != this ) 
       return false;

   // ... //
});

你必须返回false,以避免在子元素中触发点击事件。修订是错误的。 - dani24

10

我的解决方案:

jQuery('.foo').on('click',function(event){
    if ( !jQuery(event.target).is('.foo *') ) {
        // code goes here
    } 
});

类似于您上面的解决方案。 - user460114

7

我个人会给子元素添加一个点击处理程序,什么也不做,只是停止点击事件的传播。代码如下:

$('.example > div').click(function (e) {
    e.stopPropagation();
});

stopPropagation 和其他答案建议的返回 false 有什么区别? - Crashalot
我认为在这种情况下它们的功能是相同的,但我认为阻止事件传播更清晰地表明了正在进行的操作的目的,并且留下了更好的理解为什么要这样做的机会。但这是有争议的。 - Noahone
2
感谢澄清。似乎 stopPropagation 更加干净,因为它不会阻止子元素上发生的事件,而这可能会在使用 return false 时发生。 - Crashalot

0
这是一个例子。绿色正方形是父元素,黄色正方形是子元素。
希望这可以帮到你。

var childElementClicked;

$("#parentElement").click(function(){

  $("#childElement").click(function(){
     childElementClicked = true;
  });

  if( childElementClicked != true ) {

   // It is clicked on parent but not on child.
      // Now do some action that you want.
      alert('Clicked on parent');
   
  }else{
      alert('Clicked on child');
    }
    
    childElementClicked = false;
 
});
#parentElement{
width:200px;
height:200px;
background-color:green;
position:relative;
}

#childElement{
margin-top:50px;
margin-left:50px;
width:100px;
height:100px;
background-color:yellow;
position:absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="parentElement">
  <div id="childElement">
  </div>
</div>


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