jquery stop child que desencadena el evento padre

208

Tengo un div al que he adjuntado un onclickevento. en este div hay una etiqueta con un enlace. Cuando hago clic en el enlace, onclicktambién se activa el evento desde el div. ¿Cómo puedo desactivar esto para que si se hace clic en el enlace en el div onclickno se active?

guión:

$(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>
Juan
fuente

Respuestas:

412

Hacer esto:

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

Si quieres leer más sobre .stopPropagation (), mira aquí .

Nick Craver
fuente
2
si ayuda a alguien, he sustituido $(".header a")con $(".header *")y tengo que hayan sido designados niño (div, formas, de entrada, etc.).
aldo.roman.nurena
1
e.stopPropagation (); debe escribirse en la primera línea, a menos que no funcione!
ehsan
2
lamentablemente este método impide que la relcaja de luz configurada funcione
eapo
55
La respuesta a continuación de xr280xr es mucho mejor, ya que no interfiere con los posibles eventos de los niños.
Alexander Jank
1
Creas más problemas de los que resuelves. Imagine complementos de terceros que escuchan eventos de clic en el elemento del documento. Nunca sabrán sobre esos clics. Ver el comentario sobre lightbox.
Salman A
100

O, en lugar de tener un controlador de eventos adicional para evitar otro controlador, puede usar el argumento de objeto de evento pasado a su controlador de eventos de clic para determinar si se hizo clic en un elemento secundario. targetserá el elemento seleccionado y currentTargetserá el 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
fuente
8
Para mí, esta es una solución más elegante ya que no tiene que agregar un preventDefault () explícito a cada elemento secundario.
Ryan Griggs
55
Y funciona si tiene eventos independientes sobre el niño a diferencia de la respuesta aceptada. Definitivamente una solución mejor y más limpia
BozanicJosip
2
En la mayoría de los casos, esto no le importará, pero si por alguna razón necesita admitir IE6-8, no es asícurrentTarget . Una solución alternativa es reemplazarlo con this, como se sugiere en otra respuesta .
Alexander Jank
Esta es una solución más limpia que configurar un oyente adicional para capturar clics.
Micros
este código funcionó mejor para mí` var target = $ (e.target); if (! target.is ("span")) return; `
Cr1xus
17

Mejor manera usando on () con encadenamiento como,

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

Las respuestas aquí tomaron la pregunta del OP demasiado literalmente. ¿Cómo se pueden expandir estas respuestas en un escenario donde hay MUCHOS elementos secundarios, no solo una <a>etiqueta? Aquí hay una manera.

Supongamos que tiene una galería de fotos con un fondo oscurecido y las fotos centradas en el navegador. Cuando hace clic en el fondo negro (pero no hay nada dentro), desea que se cierre la superposición.

Aquí hay algunos posibles 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>

Y así es como funcionaría el JavaScript:

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

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

Esto detendrá los eventos de clic de elementos dentro .contentsde cada investigación, .gallerypor lo que la galería se cerrará solo cuando haga clic en el área de fondo negro desvanecido, pero no cuando haga clic en el área de contenido. Esto se puede aplicar a muchos escenarios diferentes.

Gavin
fuente
4

Me topé con esta pregunta, buscando otra respuesta.

Quería evitar que todos los niños activen a los padres.

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
fuente
0

O esto:

$(document).ready(function(){
    $(".header").click(function(){
        $(this).children(".children").toggle();
    });
   $(".header a").click(function(e) {
        return false;
   });
});
usuario719004
fuente
2
@ Halcyon991 e se pasa de cualquier manera a través de argumentos, e es solo una referencia
qodeninja
@qodeninja Sí, pero una adición de personaje innecesaria si no se usa.
Halcyon991
No tiene sentido agregar return falseal enlace, debe ser cliqueable.
eapo
0

La solución más simple es agregar este CSS a los hijos:

.your-child {
    pointer-events: none;
}
Muelle
fuente
Necesitaba esto para la etiqueta de fuente no deseada agregada por Wordpress y funcionó para mí
Ndm Gjr
-1

Una forma más corta de hacerlo:

$('.header').on('click', function () {
    $(this).children('a').on('click', function(e) {
        e.stopPropagation();
        $(this).siblings('.children').toggle();
    });
});
Andreas 'aNdy' Berggreen
fuente
Pero ... Esto no hace nada al hacer clic en el encabezado.
Liora Haydont
Cada vez que hace clic en el encabezado, esto agrega un nuevo evento de clic a los elementos secundarios ('a').
Frank Forte