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.

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>


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


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

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;

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/


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

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)


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

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>


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


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>

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.