¿Cómo hacer que el evento de clic SOLO se active en DIV para padres, no para niños?

211

Tengo un DIV con una clase foobar, y algunos DIV dentro de ese DIV que no están clasificados, pero supongo que están heredando la foobarclase:

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

Quiero que se active solo cuando haga clic en algún lugar del DIV pero no en sus DIV secundarios.

CaptSaltyJack
fuente

Respuestas:

440

Si el e.targetes el mismo elemento que this, no ha hecho clic en un descendiente.

$('.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>

usuario1106925
fuente
Esa respuesta explica este comentario
gdoron está apoyando a Monica
@ gdoron: Adam está siendo demasiado amable. :)
1
Hola @vicky Solo para su información, JavaScript tiene dos tipos diferentes de comparación de igualdad de valores. El ===o !==utiliza el "Algoritmo de comparación de igualdad estricto" , mientras que el ==y !=utiliza el "Algoritmo de comparación de igualdad abstracta" , que es de tipo coercitivo. La sabiduría general es usar siempre una comparación estricta a menos que haya una necesidad específica del tipo coercitivo (ya que sus reglas son un poco complejas) . En este caso, debido a que los objetos se están comparando, realmente no hace la diferencia, pero encontrará que la mayoría de las personas aún se apegarán a la comparación estricta .
1
@vicky: Eso está bien. Aún es correcto. Solo dejándote JS tiene los diferentes operadores. ;-)
3
Esta es una buena respuesta porque también puede funcionar con Vanilla JS addEventListener y no es específica de jQuery.
Michael Giovanni Pumo
64

Hay otra forma que funciona si no te importa solo apuntar a navegadores más nuevos. Solo agrega el CSS

pointer-events: none;

a cualquier hijo del div que desee capturar el clic. Aquí están las tablas de soporte.

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

hobberwickey
fuente
13
Sé que debo evitar escribir comentarios de 'gracias', pero puedo besarte el pie por esto :-)
Simona Adriani
@SimonaAdriani ¿eh?
n3wb
Gracias, hice lo mismo, pero estoy luchando por escribir un caso de prueba de unidad a su alrededor. ¿Cómo puedo asegurarme de clickque el activador de evento de clic programático debe estar bloqueado?
Pankaj Parkar
29

Puedes usar el burbujeo a tu favor:

$('.foobar').on('click', function(e) {
    // do your thing.
}).on('click', 'div', function(e) {
    // clicked on descendant div
    e.stopPropagation();
});
o yo
fuente
Esto parece una buena solución para mi escenario específico, ya que solo quiero excluir los clics en los <a>elementos descendientes . Solo hay un problema: cuando hago clic con el botón central en ellos, el evento aún se dispara (probado en Google Chrome). ¿Hay una variante de esto que también lo impide?
cgogolin
@cgogolin, mira esto: stackoverflow.com/questions/12197122/…
Jessica
28

No obtuve la respuesta aceptada para trabajar, pero esto parece funcionar, al menos en vanilla JS.

if(e.target !== e.currentTarget) return;
Jens Törnell
fuente
1
e.currentTarget es más preciso que hacer referencia thisporque el objeto al que thisapunta puede cambiar según el alcance y el contexto desde donde se llama
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)
});

Esto detendrá la propagación (burbujeo) del clickevento en cualquiera de los elementos secundarios del .foobarelemento (s) para que el evento no llegue al.foobar elementos para activar sus controladores de eventos.

Aquí hay una demostración: http://jsfiddle.net/bQQJP/

Jaspe
fuente
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
fuente
2

Tuve el mismo problema y se me ocurrió esta solución (basada en las otras respuestas)

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

Básicamente dice que si el objetivo es el div, ejecute el código; de lo contrario, no haga nada (no lo oculte)

Wonx2150
fuente
1

Mi caso es similar, pero esta es una ocasión en la que tienes pocos foobar -s y desea cerrar solo uno por cada clic:

Encuentra el caso de los padres

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

Encontrar caso de niño

$(".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
fuente
1

Puede usar event.currentTarget. Solo hará clic en el evento elemnt que obtuvo el evento.

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

Dejan Markovic
fuente
1

Si no puede usar pointer-events: none;y está apuntando a navegadores modernos, puede usar composedPathpara detectar un clic directo en el objeto de la siguiente manera:

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

Puede leer más sobre compositePath aquí: https://developer.mozilla.org/en-US/docs/Web/API/Event/composedPath

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