2012-06-01 18 views
13

Usando jQuery, ¿cómo se detectan los clics no en elementos específicos y se realiza una acción en consecuencia?Documento, haga clic en no en los elementos jQuery

que tienen la siguiente JavaScript

$('#master').click(function() { 
    $('#slave').toggle(); 
}); 

$(document).not('#master','#slave').click(function() { 
    $('#slave').hide(); 
}); 

y no puedo ver donde estoy saliendo mal lógicamente. Se puede ver un ejemplo vivo here

+1

vinculando una instancia de su manejador de clics a cada elemento DOM (excepto dos) va a ser terrible en el rendimiento. – jbabey

+1

La razón por la cual su versión no funciona es porque está probando si el elemento 'document' no tiene' master' o 'slave' como su ID. Esto siempre es cierto (el 'document' de IIRC no puede tener una ID), por lo que el controlador está vinculado al 'documento' y cada clic hará que se oculte' slave '. Luego, debido a la propagación del evento, el evento 'click' de' # master' saltará al 'document' donde ocultará' # slave', aunque '# master' simplemente lo alteró. Debes probar 'event.target' para que esto funcione. –

Respuesta

32

Puesto que usted está de unión al evento click en el documento, puede utilizar event.target para obtener el elemento que inicia el evento:

$(document).click(function(event) { 
    if (!$(event.target).is("#master, #slave")) { 
     $("#slave").hide(); 
    } 
}); 

EDIT: Como Mattias con razón señala en su comentario, el código anterior no identificará los eventos de clics provenientes de los descendientes de #master y #slave (si hay alguno). En esta situación, se puede utilizar para comprobar closest() objetivo del evento:

$(document).click(function(event) { 
    if (!$(event.target).closest("#master, #slave").length) { 
     $("#slave").hide(); 
    } 
}); 
+1

Si '# master' o' # slave' tienen elementos secundarios, necesita usar 'closer' en lugar de' is' para que funcione en esos elementos secundarios. –

+0

@Mattias, muy cierto. Respuesta actualizada en consecuencia, gracias :) –

+0

Este es un mal sustituto para ['delegate'] (http://api.jquery.com/delegate) que ya está implementado en jQuery. – zzzzBov

2

¿Este código de hacer lo que quiera? (No del todo seguro de si he entendido bien)

$('body').on('click', '*:not(#master, #slave)', function() { 
    $('#slave').hide(); 
}); 

http://jsfiddle.net/gZ4Hz/8/

1

Otro pensamiento, que pueden no estar funcionando porque su navegador no hagan quizás body a la altura del 100%; Intenta ajustar tu base de css para arreglar la altura del cuerpo y luego un par de pensamientos más.

e.stopPropagation(): Evita que el evento burbujee el árbol DOM, evitando que se notifique a ningún controlador principal del evento.

Así que si cambia el primer código de clic al siguiente:

$('#master').click(function(e) { 
    e.stopPropagation(); 
    $('#slave').toggle(); 
}); 

entonces se podría cambiar el distintivo de llamada de la segunda también:

$("body, body *").not('#master, #slave').click(function(e) { 
    $('#slave').hide(); 
}); 

y que debe cubrirlo. ¡Darle una oportunidad! o vea this jsFiddle

+0

¡Perfecto! Me acabas de hacer un hombre feliz :) – jacktheripper

+1

Enlazar los controladores de eventos a todos los demás elementos no es una buena idea. La solución de Frédéric Hamidi es mejor. –

+1

Esa es una solución horrible. Está vinculando ese segundo controlador por separado a ** cada elemento en el DOM **. Esto no solo es terriblemente ineficiente, sino que tampoco funcionará con los elementos insertados dinámicamente añadidos al DOM después. La solución de Frédéric es mucho más elegante y (lo que es más importante) funciona en todas las situaciones. –

2

La delegación de eventos ha sido soportada desde hace mucho por jQuery. La dificultad radica en crear el selector apropiado. Originalmente, se usó delegate, pero más recientemente se debe usar el formulario delegado de on.

El propósito de la delegación de eventos es escuchar eventos en elementos secundarios e invocar a los manejadores de eventos enlazados en esos elementos como si hubieran sido vinculados al elemento hijo, en lugar de al padre. Esto significa que en lugar de vincular controladores a cada elemento en el DOM, está vinculando un controlador a cada elemento en la selección inicial (document es un elemento único).Esto también hace que para una forma sencilla de utilizar un solo selector de unirse a un conjunto siempre cambiante de elementos, como nuevos elementos y se propague a sus eventos a document si son o no existían cuando el controlador de eventos inicial fue obligado:

$(document).on('click', '*:not(#master, #master *, #slave, #slave *)', function (e) { 
    //this will reference the clicked element 
}); 

Además, tenga en cuenta que no solo dije que los elementos no deben ser #master o #slave, sino no deben ser hijos de #master o #slave tampoco.

+0

Muy interesante. Normalmente evito los selectores '*' tanto en CSS (la mayoría de las veces basta con la cascada) como en jQuery (hacer coincidir un subárbol completo puede ser costoso), pero acepto que esto debería funcionar al menos tan bien como 'event.target' combinado con 'closest()' en los navegadores modernos. Ahora tengo curiosidad sobre los perfs, tal vez establezca un punto de referencia en mi copioso tiempo libre. Saludos :) –

0

Las respuestas de Fredrik funcionan para los elementos ya presentes en el documento, pero no funcionó para los elementos recuperados por las llamadas ajax. Intenté lo siguiente y me funciona. Compartir el código para futuros codificadores Ajax.

$(document).on('click',function(event) { 
     if (!$(event.target).closest("#selector").length) { 
      if ($('#selector').is(":visible")) 
       $('#selector').slideUp(); 
     } 
    }); 

Lo habría publicado como comentario pero no tengo suficiente reputación para eso.

Cuestiones relacionadas