jquery parar filho acionando evento pai

208

Eu tenho uma div à qual eu anexei um onclickevento. nesta div há uma tag com um link. Quando clico no link, oonclick evento da div também é acionado. Como posso desativar isso para que, se o link for clicado na divonclick não seja acionado?

roteiro:

$(document).ready(function(){
    $(".header").bind("click", function(){
         $(this).children(".children").toggle();
    });
})

Código HTML:

<div class="header">
    <a href="link.html">some link</a>
    <ul class="children">
        <li>some list</li>
    </ul>
</div>
John
fonte

Respostas:

411

Faça isso:

$(document).ready(function(){
    $(".header").click(function(){
        $(this).children(".children").toggle();
    });
   $(".header a").click(function(e) {
        e.stopPropagation();
   });
});

Se você quiser ler mais sobre .stopPropagation (), consulte aqui .

Nick Craver
fonte
2
se ajuda alguém, eu substituído $(".header a")com $(".header *")e obteve qualquer criança selecionada (div, formulários, entrada, etc).
Aldo.roman.nurena
1
e.stopPropagation (); deve ser escrito na primeira linha, a menos que não funcione!
ehsan
2
Infelizmente este método de prevenção da relLuz configurado para a função
DEAC
5
A resposta abaixo do xr280xr é muito melhor, pois não interfere com os possíveis eventos das crianças.
precisa
1
Você cria mais problemas do que resolve. Imagine plugins de terceiros ouvindo eventos de clique no elemento do documento. Eles nunca saberão sobre esses cliques. Veja o comentário sobre o lightbox.
Salman A
100

Ou, em vez de ter um manipulador de eventos extra para impedir outro manipulador, você pode usar o argumento Event Object passado para o manipulador de eventos click para determinar se um filho foi clicado. targetserá o elemento clicado e currentTargetserá a div .header:

$(".header").click(function(e){
     //Do nothing if .header was not directly clicked
     if(e.target !== e.currentTarget) return;

     $(this).children(".children").toggle();
});
xr280xr
fonte
8
Para mim, essa é uma solução mais elegante, pois você não precisa adicionar um preventDefault () explícito a cada elemento filho.
Ryan Griggs
5
E funciona se você tiver eventos independentes na criança, diferentemente da resposta aceita. Definitivamente, a solução mais limpa e melhor
BozanicJosip
2
Na maioria das circunstâncias, você não se preocupará com isso, mas, por qualquer motivo, você precisa dar suporte ao IE6-8, eles não o têmcurrentTarget . Uma solução alternativa é substituí-lo por this, como sugerido em outra resposta .
Alexander Jank
Essa é uma solução mais limpa do que definir um ouvinte extra para capturar apenas cliques.
Micros
esse código funcionou melhor para mim` var target = $ (e.target); if (! target.is ("span")) return; `
Cr1xus
17

Melhor maneira usando on () com encadeamento como,

$(document).ready(function(){
    $(".header").on('click',function(){
        $(this).children(".children").toggle();
    }).on('click','a',function(e) {
        e.stopPropagation();
   });
});
Rohan Kumar
fonte
4

As respostas aqui levaram a pergunta do OP muito literalmente. Como essas respostas podem ser expandidas para um cenário em que há MUITOS elementos filhos, não apenas um<a> tag? Aqui está uma maneira.

Digamos que você tenha uma galeria de fotos com um fundo escuro e as fotos centralizadas no navegador. Ao clicar no plano de fundo preto (mas não em nada dentro dele), você deseja que a sobreposição seja fechada.

Aqui está um possível HTML:

<div class="gallery" style="background: black">
    <div class="contents"> <!-- Let's say this div is 50% wide and centered -->
        <h1>Awesome Photos</h1>
        <img src="img1.jpg"><br>
        <img src="img2.jpg"><br>
        <img src="img3.jpg"><br>
        <img src="img4.jpg"><br>
        <img src="img5.jpg">
    </div>
</div>

E aqui está como o JavaScript funcionaria:

$('.gallery').click(
    function()
    {
        $(this).hide();
    }
);

$('.gallery > .contents').click(
    function(e) {
        e.stopPropagation();
    }
);

Isso interromperá os eventos de clique dos elementos internos .contentsde todas as pesquisas, .gallerypara que a galeria seja fechada apenas quando você clicar na área de fundo preto desbotada, mas não quando você clicar na área de conteúdo. Isso pode ser aplicado a muitos cenários diferentes.

Gavin
fonte
4

Eu me deparei com essa pergunta, procurando outra resposta.

Eu queria impedir que todas as crianças acionassem os pais.

JavaScript:

document.getElementById("parent").addEventListener("click",  function (e) {
    if (this !== event.target) return;
    // Do something
});

jQuery:

$("#parent").click(function () {
    // Do something
}).children().on("click", function (e) {
    e.stopPropagation();
});
Daan
fonte
0

Ou isto:

$(document).ready(function(){
    $(".header").click(function(){
        $(this).children(".children").toggle();
    });
   $(".header a").click(function(e) {
        return false;
   });
});
user719004
fonte
2
@ Halcyon991 e é passado em uma ou outra maneira através de argumentos, e é apenas uma referência
qodeninja
@qodeninja Sim, mas uma adição desnecessária de caracteres, se não for usada.
precisa saber é o seguinte
Não adianta adicionar return falseao link, ele deve ser clicável.
276 Epo
0

A solução mais simples é adicionar esse CSS aos filhos:

.your-child {
    pointer-events: none;
}
Pier
fonte
Eu precisava disso para a tag de fonte indesejada adicionada pelo Wordpress e funcionou para mim
Ndm Gjr
-1

Uma maneira mais curta de fazer isso:

$('.header').on('click', function () {
    $(this).children('a').on('click', function(e) {
        e.stopPropagation();
        $(this).siblings('.children').toggle();
    });
});
Andreas 'aNdy' Berggreen
fonte
Mas ... Isso não faz nada ao clicar no cabeçalho.
Liora Haydont 29/08/19
Sempre que você clica no cabeçalho, isso adiciona um novo evento de clique aos filhos ('a').
Frank Forte