Como ter o evento de clique APENAS acionado no DIV pai, não nos filhos?

211

Eu tenho um DIV com um DIV classificado foobare alguns DIV dentro desse DIV que não são classificados, mas suponho que eles estejam herdando a foobarclasse:

$('.foobar').on('click', function() { /*...do stuff...*/ });

Quero que isso seja acionado apenas ao clicar em algum lugar no DIV, mas não nos DIVs filhos.

CaptSaltyJack
fonte

Respostas:

439

Se o e.targetmesmo for o elemento que thisvocê não clicou em um descendente.

$('.foobar').on('click', function(e) {
  if (e.target !== this)
    return;
  
  alert( 'clicked the foobar' );
});
.foobar {
  padding: 20px; background: yellow;
}
span {
  background: blue; color: white; padding: 8px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class='foobar'> .foobar (alert) 
  <span>child (no alert)</span>
</div>

user1106925
fonte
Essa resposta explica este comentário
gdoron está apoiando Monica
@gdoron: Adam está sendo muito gentil. :)
1
Oi @vicky. Apenas para sua informação, o JavaScript tem dois tipos diferentes de comparação de igualdade de valor. O ===ou !==usa o "Algoritmo estrito de comparação de igualdade" , enquanto o ==e !=usa o "Algoritmo abstrato de comparação de igualdade" , que é do tipo coercitivo. A sabedoria geral é sempre usar comparação estrita, a menos que haja uma necessidade específica do tipo coercitivo (já que suas regras são um pouco complexas) . Nesse caso, como os objetos estão sendo comparados, isso realmente não faz diferença, mas você verá que a maioria das pessoas ainda mantém a comparação estrita .
1
@ vicky: Tudo bem. Ainda está correto. Apenas deixando você JS ter os diferentes operadores. ;-)
3
Essa é uma boa resposta, pois também pode funcionar com o addEventListener do Vanilla JS e não é específico do jQuery.
Michael Giovanni Pumo
64

Existe outra maneira de funcionar, se você não se importa de segmentar navegadores mais recentes. Basta adicionar o CSS

pointer-events: none;

a qualquer filho da div que você deseja capturar o clique. Aqui estão as tabelas de suporte

http://caniuse.com/#feat=pointer-events

hobberwickey
fonte
13
Saiba que devo evitar escrever comentários de agradecimento, mas posso beijar-lhe o pé por isso :-)
Simona Adriani
@SimonaAdriani huh?
N3wb
Obrigado, fiz da mesma maneira, mas estou lutando para escrever um caso de teste de unidade em torno dele. Como garantir que o clickacionador de evento de clique programático seja bloqueado?
Pankaj Parkar
29

Você pode usar bolhas a seu favor:

$('.foobar').on('click', function(e) {
    // do your thing.
}).on('click', 'div', function(e) {
    // clicked on descendant div
    e.stopPropagation();
});
ori
fonte
Parece uma boa solução para o meu cenário específico, pois eu quero excluir apenas cliques nos <a>elementos descendentes . Há apenas um problema: quando clico no meio deles, o evento ainda é acionado (testado no Google Chrome). Existe uma variante disso que também impede isso?
Cgogolin # 19/15
@cgogolin, dê uma olhada no seguinte: stackoverflow.com/questions/12197122/…
Jessica
28

Não recebi a resposta aceita para o trabalho, mas isso parece funcionar, pelo menos no JS vanilla.

if(e.target !== e.currentTarget) return;
Jens Törnell
fonte
1
e.currentTarget é mais preciso do que fazendo referência thisporque o objeto que thisestá apontando para a mudança pode dependendo do escopo e do contexto de onde é chamado
eballeste
20
//bind `click` event handler to the `.foobar` element(s) to do work,
//then find the children of all the `.foobar` element(s)
//and bind a `click` event handler to them that stops the propagation of the event
$('.foobar').on('click', function () { ... }).children().on('click', function (event) {
    event.stopPropagation();
    //you can also use `return false;` which is the same as `event.preventDefault()` and `event.stopPropagation()` all in one (in a jQuery event handler)
});

Isso interromperá a propagação (subida) do clickevento em qualquer um dos elementos filhos do (s) .foobarelemento (s), para que o evento não atinja o .foobar(s) elemento (s) para disparar seus manipuladores de eventos.

Aqui está uma demonstração: http://jsfiddle.net/bQQJP/

Jaspe
fonte
3
$(".advanced ul li").live('click',function(e){
    if(e.target != this) return;
    //code
    // this code will execute only when you click to li and not to a child
})
Michalis
fonte
2

Eu tive o mesmo problema e surgiu com esta solução (com base nas outras respostas)

 $( ".newsletter_background" ).click(function(e) {
    if (e.target == this) {
        $(".newsletter_background").hide();
    } 
});

Basicamente, diz que se o destino é a div, execute o código, caso contrário não faça nada (não o oculte)

Wonx2150
fonte
1

Meu caso é semelhante, mas é a ocasião em que você tem poucos foobar-s e deseja fechar apenas um - por um clique:

Localizar caso pai

$(".foobar-close-button-class").on("click", function () {
    $(this).parents('.foobar').fadeOut( 100 );
    // 'this' - means that you finding some parent class from '.foobar-close-button-class'
    // '.parents' -means that you finding parent class with name '.foobar'
});

Localizar caso filho

$(".foobar-close-button-class").on("click", function () {
    $(this).child('.foobar-close-button-child-class').fadeOut( 100 );
    // 'this' - means that you finding some child class from '.foobar-close-button-class'
    // '.child' -means that you finding child class with name '.foobar-close-button-child-class'
});
Wukadin
fonte
1

Você pode usar event.currentTarget. Ele fará clique apenas no evento que não obteve o evento.

target = e => {
    console.log(e.currentTarget);
  };
<ul onClick={target} className="folder">
      <li>
        <p>
          <i className="fas fa-folder" />
        </p>
      </li>
    </ul>

Dejan Markovic
fonte
1

Se você não pode usar pointer-events: none;e está direcionando navegadores modernos, pode composedPathdetectar um clique direto no objeto da seguinte maneira:

element.addEventListener("click", function (ev) {
    if (ev.composedPath()[0] === this) {
        // your code here ...
    }
})

Você pode ler mais sobre o composPath aqui: https://developer.mozilla.org/en-US/docs/Web/API/Event/composedPath

Xenxier
fonte
0

// if its li get value 
document.getElementById('li').addEventListener("click", function(e) {
                if (e.target == this) {
                    UodateNote(e.target.id);
                }
                })
                
                
                function UodateNote(e) {

    let nt_id = document.createElement("div");
    // append container to duc.
    document.body.appendChild(nt_id);
    nt_id.id = "hi";
    // get conatiner value . 
    nt_id.innerHTML = e;
    // body...
    console.log(e);

}
li{
 cursor: pointer;
    font-weight: bold;
  font-size: 20px;
    position: relative;
    width: 380px;
    height: 80px;
    background-color: silver;
    justify-content: center;
    align-items: center;
    text-align: center;
    margin-top: 0.5cm;
    border: 2px solid purple;
    border-radius: 12%;}
    
    p{
     cursor: text;
  font-size: 16px;
   font-weight: normal;
    display: block;
    max-width: 370px;
    max-height: 40px;
    overflow-x: hidden;}
<li id="li"><p>hi</p></li>

Omar bakhsh
fonte