jQuery: la función de clic excluye a los hijos.

144

Tratando de comprender la función jQuery ".not ()", y me encuentro con un problema. Me gustaría que el div primario sea "cliqueable", pero si un usuario hace clic en un elemento secundario, no se llama al script.

$(this).not(children()).click(function(){
   $(".example").fadeOut("fast");
});

el html:

<div class="example">
   <div>
      <p>This content is not affected by clicks.</p>
   </div>
</div>
supertitulado
fuente

Respuestas:

198

Para hacer esto, detenga el clic en el niño usando .stopPropagation :

$(".example").click(function(){
  $(this).fadeOut("fast");
}).children().click(function(e) {
  return false;
});

Esto evitará que los clics secundarios aumenten más allá de su nivel para que los padres no reciban el clic.

.not() se usa un poco diferente, filtra elementos fuera de su selector, por ejemplo:

<div class="bob" id="myID"></div>
<div class="bob"></div>

$(".bob").not("#myID"); //removes the element with myID

Para hacer clic, su problema es que el clic en un elemento secundario burbujea hacia el elemento primario , no es que haya adjuntado inadvertidamente un controlador de clic al elemento secundario.

Nick Craver
fuente
Gracias Nick, no creo que esto sea lo que estaba buscando. Lamento no haber sido claro en mi pregunta. Quiero que todo el div.example se desvanezca, solo cuando se hace clic en el elemento principal, no cuando se hace clic en el elemento secundario. La razón de esto es que me gustaría que el usuario pueda hacer clic en el texto del párrafo y no tener el texto fadeOut. Si el usuario hace clic en el div externo (div primario), entonces todo se desvanecerá.
superUntitled
@superUntitled - Gracias por la aclaración ... la respuesta se actualizó para hacer esto, pruébalo.
Nick Craver
18
@Asaf: use en e.stopPropagation();lugar de return false;para ese caso.
Nick Craver
2
También puede usar }).find('.classes-to-ignore').click(function(e) {para elegir elementos secundarios específicos
Paul Mason,
55
No entiendo por qué le dices que use e.stopPropagation()y luego use return falseen su lugar. return falsees equivalente a e.preventDefault(); e.stopPropagation()lo que podría tener efectos secundarios inesperados.
Steen Schütt
183

Estoy usando el siguiente marcado y me encontré con el mismo problema:

<ul class="nav">
    <li><a href="abc.html">abc</a></li>
    <li><a href="def.html">def</a></li>
</ul>

Aquí he usado la siguiente lógica:

$(".nav > li").click(function(e){
    if(e.target != this) return; // only continue if the target itself has been clicked
    // this section only processes if the .nav > li itself is clicked.
    alert("you clicked .nav > li, but not it's children");
});

En términos de la pregunta exacta, puedo ver que funciona de la siguiente manera:

$(".example").click(function(e){
   if(e.target != this) return; // only continue if the target itself has been clicked
   $(".example").fadeOut("fast");
});

o, por supuesto, al revés:

$(".example").click(function(e){
   if(e.target == this){ // only if the target itself has been clicked
       $(".example").fadeOut("fast");
   }
});

Espero que ayude.

MatCarey
fuente
28
Creo que esta es la mejor solución. No interfiere con los niños de ninguna manera y debería funcionar mejor ya que no registra potencialmente miles de devoluciones de llamadas si hay miles de niños.
LucasB
44
@ l2aelba: debería usar .on("click", ...)en versiones recientes de jQuery como .live()ha quedado en desuso desde v1.7. Ver api.jquery.com/live
Chris
Sí, @Chris publiqué el 16 de noviembre de 12 a las 10:12
l2aelba el
Lo sentimos, probablemente no necesité hacer referencia a su identificación. Agregué el comentario en gran parte para cualquiera que lea esta respuesta.
Chris
1
Esta respuesta es mejor que la respuesta aceptada, ya que no interrumpe ningún evento de clic en elementos secundarios
cameronjonesweb
24

O puedes hacer también:

$('.example').on('click', function(e) { 
   if( e.target != this ) 
       return false;

   // ... //
});
dani24
fuente
Debe devolver false para evitar el evento click en los elementos secundarios. La revisión fue incorrecta
dani24
6

Mi solución:

jQuery('.foo').on('click',function(event){
    if ( !jQuery(event.target).is('.foo *') ) {
        // code goes here
    } 
});
npl len
fuente
Similar a la solución sobre la tuya.
user460114
3

Personalmente, agregaría un controlador de clic al elemento secundario que no hizo nada más que detener la propagación del clic. Entonces se vería algo así como:

$('.example > div').click(function (e) {
    e.stopPropagation();
});
Noahone
fuente
¿Cuál es la diferencia entre stopPropagationy devolver falso como sugieren otras respuestas?
Crashalot
Creo que en este caso funcionarían igual, pero creo que detener la propagación es más claro para el propósito de lo que se está haciendo y deja una mejor oportunidad de entender por qué se hace más tarde. Pero es discutible.
Noahone
gracias por la aclaración. parece que stopPropagationpuede estar más limpio, ya que no detendrá la ocurrencia de eventos en elementos secundarios, lo que puede suceder con return false.
Crashalot
0

Aquí hay un ejemplo. El cuadrado verde es padre y el cuadrado amarillo es elemento hijo.

Espero que esto ayude.

var childElementClicked;

$("#parentElement").click(function(){

		$("#childElement").click(function(){
		   childElementClicked = true;
		});

		if( childElementClicked != true ) {

			// It is clicked on parent but not on child.
      // Now do some action that you want.
      alert('Clicked on parent');
			
		}else{
      alert('Clicked on child');
    }
    
    childElementClicked = false;
	
});
#parentElement{
width:200px;
height:200px;
background-color:green;
position:relative;
}

#childElement{
margin-top:50px;
margin-left:50px;
width:100px;
height:100px;
background-color:yellow;
position:absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="parentElement">
  <div id="childElement">
  </div>
</div>

Nole
fuente