jQuery: функция щелчка исключает детей.

144

Попытка обернуть голову вокруг функции 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>
superUntitled
источник

Ответы:

198

Чтобы сделать это, остановите щелчок на дочернем элементе, используя .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

При щелчке ваша проблема заключается в том, что щелчок дочернего элемента всплывает над родителем , а не в том, что вы случайно прикрепили обработчик щелчков к дочернему элементу.

Ник Крейвер
источник
спасибо ник, я не думаю, что это то, что я искал. Прошу прощения, что мне не ясно в моем вопросе. Я хочу, чтобы весь div.example был fadeOut, только при щелчке по родительскому элементу, а не при щелчке по дочернему элементу. Причина этого в том, что я хотел бы, чтобы пользователь мог щелкнуть текст абзаца и не иметь текст fadeOut. Если пользователь нажимает на внешний div (родительский div), то все исчезнет.
названия
@superUntitled - Спасибо за разъяснения ... ответ обновлен, чтобы сделать это, попробуйте.
Ник Крейвер
18
@Asaf - использовать e.stopPropagation();вместо return false;этого.
Ник Крейвер
2
Вы также можете использовать, }).find('.classes-to-ignore').click(function(e) {чтобы выбрать определенные дочерние элементы
Пол Мейсон
5
Я не понимаю, почему вы говорите ему использовать, e.stopPropagation()а затем использовать return falseвместо этого. return falseэквивалентно, e.preventDefault(); e.stopPropagation()поэтому у него могут быть неожиданные побочные эффекты.
Стин Шютт,
183

Я использую следующую разметку и столкнулся с той же проблемой:

<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");
   }
});

Надеюсь, это поможет.

MatCarey
источник
28
Я думаю, что это лучшее решение. Он никак не мешает детям и должен работать лучше, поскольку потенциально не регистрирует тысячи обратных вызовов, если есть тысячи детей.
LucasB
4
@ l2aelba - вы должны использовать .on("click", ...)в последних версиях jQuery .live(), что устарело с v1.7. См. Api.jquery.com/live
Крис
Да, @Chris я отправил 16 ноября '12 в 10:12
l2aelba
Извините, вероятно, не нужно указывать ваш идентификатор. Я добавил комментарий в основном для тех, кто читает этот ответ.
Крис
1
Этот ответ лучше принятого, так как он не прерывает события щелчка на дочерних элементах
cameronjonesweb
24

Или вы можете сделать также:

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

   // ... //
});
dani24
источник
Вы должны вернуть false, чтобы избежать события click в дочерних элементах.
Редакция
6

Мое решение:

jQuery('.foo').on('click',function(event){
    if ( !jQuery(event.target).is('.foo *') ) {
        // code goes here
    } 
});
нпл лен
источник
Похоже на решение выше вашего.
user460114
3

Лично я бы добавил обработчик кликов к дочернему элементу, который ничего не делал, кроме как остановил распространение клика. Так это будет выглядеть примерно так:

$('.example > div').click(function (e) {
    e.stopPropagation();
});
Noahone
источник
В чем разница между stopPropagationвозвратом ложных, как предлагают другие ответы?
Crashalot
Я полагаю, что в этом случае они будут работать одинаково, но я думаю, что прекращение распространения более понятно для целей того, что делается, и оставляет больше шансов понять, почему это делается позже. Но это спорно.
Ноахоне
Спасибо за разъяснения. Кажется, что он 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>

Нола
источник