jQuery: clique na função excluir filhos.

144

Tentando entender a função jQuery ".not ()" e encontrando um problema. Eu gostaria que o div pai fosse "clicável", mas se um usuário clicar em um elemento filho, o script não será chamado.

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

o html:

<div class="example">
   <div>
      <p>This content is not affected by clicks.</p>
   </div>
</div>
superUntitled
fonte

Respostas:

198

Para fazer isso, pare o clique no filho usando .stopPropagation :

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

Isso impedirá que os cliques filhos subam do nível para que os pais não recebam o clique.

.not() é usado de maneira um pouco diferente, ele filtra elementos do seu seletor, por exemplo:

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

$(".bob").not("#myID"); //removes the element with myID

Ao clicar, seu problema é que o clique em um filho é exibido na direção do pai , e não que você anexou inadvertidamente um manipulador de cliques ao filho.

Nick Craver
fonte
graças nick, eu não acho que é isso que eu estava procurando. Lamento não ter ficado claro na minha pergunta. Quero que o div.example inteiro desapareça, apenas quando o elemento pai for clicado, não quando o div filho for clicado. A razão para isso é que eu gostaria que o usuário pudesse clicar no texto do parágrafo e não ter o texto fadeOut. Se o usuário clicar na div externa (div principal), tudo desaparecerá.
superUntitled
@superUntitled - Obrigado pelo esclarecimento ... A resposta foi atualizada para fazer isso, experimente.
Nick Craver
18
@Asaf - use em e.stopPropagation();vez de return false;nesse caso.
Nick Craver
2
Você também pode usar }).find('.classes-to-ignore').click(function(e) {para escolher os elementos filho específicos
Paul Mason
5
Não entendo por que você diz para ele usar e.stopPropagation()e depois usar return false. return falseé equivalente a, e.preventDefault(); e.stopPropagation()portanto, pode ter efeitos colaterais inesperados.
Steen Schütt
183

Estou usando a seguinte marcação e havia encontrado o mesmo problema:

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

Aqui eu usei a seguinte lógica:

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

Em termos da pergunta exata, posso ver que funciona da seguinte maneira:

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

ou, é claro, o contrário:

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

Espero que ajude.

MatCarey
fonte
28
Eu acho que essa é a melhor solução. Ele não interfere nas crianças de forma alguma e deve ter um desempenho melhor, pois não registra potencialmente milhares de retornos de chamada se houver milhares de crianças.
LucasB
4
@ l2aelba - você deve usar .on("click", ...)nas versões recentes do jQuery, pois .live()está obsoleto desde a v1.7. Veja api.jquery.com/live
Chris
Sim, @ Chris eu publiquei em 16/11/12 às 10:12
l2aelba 11/11/2013
Desculpe, provavelmente não foi necessário fazer referência ao seu ID. Eu adicionei o comentário principalmente para qualquer pessoa que leia esta resposta.
31413 Chris
1
Esta resposta é melhor do que a resposta aceita, pois não interromper quaisquer eventos de clique sobre os elementos filho
cameronjonesweb
24

Ou você também pode fazer:

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

   // ... //
});
dani24
fonte
Você deve retornar false, para evitar o evento click nos elementos filhos. A revisão estava errada #
dani24
6

Minha solução:

jQuery('.foo').on('click',function(event){
    if ( !jQuery(event.target).is('.foo *') ) {
        // code goes here
    } 
});
npl len
fonte
Semelhante à solução acima da sua.
User460114
3

Pessoalmente, adicionaria um manipulador de cliques ao elemento filho que não fazia nada além de interromper a propagação do clique. Então, seria algo como:

$('.example > div').click(function (e) {
    e.stopPropagation();
});
Noahone
fonte
qual é a diferença entre stopPropagatione retornar falso como outras respostas sugerem?
Crashalot 16/03
Acredito que, nesse caso, eles funcionariam da mesma forma, mas acho que a propagação de parada é mais clara para o objetivo do que está sendo feito e deixa uma melhor chance de entender por que está sendo feito mais tarde. Mas é discutível.
Noahone 16/03
obrigado pelo esclarecimento. parece que stopPropagationpode ser mais limpo, pois não impedirá a ocorrência de eventos em elementos filho, o que pode acontecer com return false.
Crashalot 16/03
0

Aqui está um exemplo. O quadrado verde é pai e o quadrado amarelo é elemento filho.

Espero que isso ajude.

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>

Nole
fonte