Use jQuery para ocultar un DIV cuando el usuario hace clic fuera de él

968

Estoy usando este código:

$('body').click(function() {
   $('.form_wrapper').hide();
});

$('.form_wrapper').click(function(event){
   event.stopPropagation();
});

Y este HTML :

<div class="form_wrapper">
   <a class="agree" href="javascript:;">I Agree</a>
   <a class="disagree" href="javascript:;">Disagree</a>
</div>

El problema es que tengo enlaces dentro divy cuando ya no funcionan cuando se hace clic.

Scott Yu - construye cosas
fuente
66
Usando JavaScript simple puedes probar algo como esto: jsfiddle.net/aamir/y7mEY
Aamir Afridi
usando $('html')o $(document)sería mejor que$('body')
Adrien Be

Respuestas:

2485

Tuve el mismo problema, se me ocurrió esta solución fácil. Incluso funciona de forma recursiva:

$(document).mouseup(function(e) 
{
    var container = $("YOUR CONTAINER SELECTOR");

    // if the target of the click isn't the container nor a descendant of the container
    if (!container.is(e.target) && container.has(e.target).length === 0) 
    {
        container.hide();
    }
});

fuente
19
Simplemente póngalo en mi proyecto, pero con un pequeño ajuste, usando una matriz de elementos para recorrerlos todos a la vez. jsfiddle.net/LCB5W
Thomas
55
@mpelzsherman Muchas personas comentaron que el fragmento funciona en dispositivos táctiles, pero desde que se editó la publicación, estos comentarios se han desvanecido. TBH No sé si usé "mouseup" por una razón específica, pero si también funciona con "clic", no veo ninguna razón por la que no debas usar "clic".
66
Necesitaba que el contenedor se ocultara una vez con este evento, esta devolución de llamada debería destruirse cuando se usara. Para hacer eso, utilicé el espacio de nombres en el evento click con bind ("click.namespace") y cuando ocurrió el evento, llamé unbind ("click.namespace"). Y finalmente, usé $ (e.target) .closest (". Container"). Length para reconocer el contenedor ... Entonces, no
utilicé
80
Recordando usar $("YOUR CONTAINER SELECTOR").unbind( 'click', clickDocument );justo al lado .hide(). Así documentque no sigas escuchando los clics.
brasofilo
12
Para las mejores prácticas, escribí $(document).on("mouseup.hideDocClick", function () { ... });en la función que abre el contenedor y $(document).off('.hideDocClick');en la función ocultar. Usando espacios de nombres no estoy eliminando otros posibles mouseupoyentes adjuntos al documento.
campjos
204

Será mejor que vayas con algo como esto:

var mouse_is_inside = false;

$(document).ready(function()
{
    $('.form_content').hover(function(){ 
        mouse_is_inside=true; 
    }, function(){ 
        mouse_is_inside=false; 
    });

    $("body").mouseup(function(){ 
        if(! mouse_is_inside) $('.form_wrapper').hide();
    });
});
Makram Saleh
fuente
¡Qué listo! ¿Es esta técnica estándar?
Advait
@advait No lo vi usado antes. Se trata del hovercontrolador de eventos, que abre muchas posibilidades.
Makram Saleh el
55
No considero que sea una buena solución, ya que permite a las personas pensar que está bien llenar el objeto de ventana (= usando variables globales).
1
Solo para agregar algo a lo que @ prc322 dijo, puede envolver su código con una función anónima y hacer que se llame de inmediato. (function() { // ... code })(); No recuerdo el nombre de este patrón, ¡pero es muy útil! Todas las variables declaradas residirán dentro de la función y no contaminarán el espacio de nombres global.
pedromanoel
3
@ prc322 Si ni siquiera sabe cómo cambiar el alcance de una variable, entonces tiene razón, esta solución no es buena para usted ... y tampoco lo es JavaScript. Si solo está copiando y pegando código de Stack Overflow, tendrá muchos más problemas que posiblemente sobrescribir algo en el objeto de la ventana.
Gavin
87

Este código detecta cualquier evento de clic en la página y luego oculta el #CONTAINERelemento si y solo si el elemento seleccionado no era el #CONTAINERelemento ni uno de sus descendientes.

$(document).on('click', function (e) {
    if ($(e.target).closest("#CONTAINER").length === 0) {
        $("#CONTAINER").hide();
    }
});
Caso
fuente
¡¡Esto es perfecto!!
Mohd Abdul Mujib
@ 9KSoft Me alegra que haya podido ayudarte. Gracias por sus comentarios y la mejor de las suertes.
Caso
¡Esta solución funcionó perfectamente para mí usando un div como contenedor!
JCO9
76

Es posible que desee verificar el destino del evento de clic que se dispara para el cuerpo en lugar de confiar en stopPropagation.

Algo como:

$("body").click
(
  function(e)
  {
    if(e.target.className !== "form_wrapper")
    {
      $(".form_wrapper").hide();
    }
  }
);

Además, el elemento del cuerpo puede no incluir todo el espacio visual que se muestra en el navegador. Si observa que sus clics no se registran, es posible que deba agregar el controlador de clics para el elemento HTML.

David Andres
fuente
Sí, ahora los enlaces funcionan! Pero por alguna razón, cuando hago clic en el enlace, lo dispara dos veces.
Scott Yu: construye cosas el
Terminé usando una variación de esto. Primero verifico si el elemento es visible y luego si el target.hasClass lo oculto.
Hawkee
y no olvides e.stopPropagation();si tienes otro oyente de clics
Darin Kolev
2
-1. Esto oculta form_wrappercuando hace clic en uno de sus elementos secundarios, que no es el comportamiento deseado. Utilice la respuesta de prc322 en su lugar.
Mark Amery
38

Demo en vivo

El área de clic de verificación no está en el elemento de destino o en su elemento secundario

$(document).click(function (e) {
    if ($(e.target).parents(".dropdown").length === 0) {
        $(".dropdown").hide();
    }
});

ACTUALIZAR:

jQuery detener la propagación es la mejor solución

Demo en vivo

$(".button").click(function(e){
    $(".dropdown").show();
     e.stopPropagation();
});

$(".dropdown").click(function(e){
    e.stopPropagation();
});

$(document).click(function(){
    $(".dropdown").hide();
});
MaxEcho
fuente
Gracias por la actualización, ¡perfecto! ¿Funciona en dispositivos táctiles?
FFish
1
En el caso, tiene múltiples menús desplegables en una página. Creo que tendrá que cerrar todos los menús desplegables antes de abrir clickeduno. De lo contrario, stopPropagationharía posible que se abran múltiples menús desplegables al mismo tiempo.
T04435
19
$(document).click(function(event) {
    if ( !$(event.target).hasClass('form_wrapper')) {
         $(".form_wrapper").hide();
    }
});
meder omuraliev
fuente
2
Hmmm ... Si hago clic en algo DENTRO del div, el div completo desaparece por alguna razón.
Scott Yu: crea cosas el
11
En lugar de verificar si el objetivo tiene la clase, intente: if ($ (event.target) .closest ('. Form_wrapper) .get (0) == null) {$ (". Form_wrapper"). Hide (); } Esto asegurará que hacer clic en las cosas dentro del div no lo oculte.
John Haager
17

Se actualizó la solución a:

  • use mouseenter y mouseleave en su lugar
  • de vuelo estacionario use enlace de evento en vivo

var mouseOverActiveElement = false;

$('.active').live('mouseenter', function(){
    mouseOverActiveElement = true; 
}).live('mouseleave', function(){ 
    mouseOverActiveElement = false; 
});
$("html").click(function(){ 
    if (!mouseOverActiveElement) {
        console.log('clicked outside active element');
    }
});
benvds
fuente
1
.liveahora está en desuso ; utilizar .onen su lugar.
Brett
9

Demostración en vivo con ESCfuncionalidad

Funciona tanto en computadoras de escritorio como en dispositivos móviles

var notH = 1,
    $pop = $('.form_wrapper').hover(function(){ notH^=1; });

$(document).on('mousedown keydown', function( e ){
  if(notH||e.which==27) $pop.hide();
});

Si en algún caso necesita asegurarse de que su elemento sea realmente visible cuando haga clic en el documento: if($pop.is(':visible') && (notH||e.which==27)) $pop.hide();

Roko C. Buljan
fuente
8

¿No funcionaría algo como esto?

$("body *").not(".form_wrapper").click(function() {

});

o

$("body *:not(.form_wrapper)").click(function() {

});
MRVDOG
fuente
44
Esta respuesta no es correcta. Al igual que muchas respuestas aquí, esto ocultará .form_wrappercuando haga clic en sus elementos secundarios (entre otros problemas).
Mark Amery
6

Incluso aguijón:

$("html").click(function(){ 
    $(".wrapper:visible").hide();
});
Olivenbaum
fuente
44
Esta respuesta no es correcta. Esto ocultará .wrapperno importa dónde haga clic en la página, que no es lo que se le solicitó.
Mark Amery
6

En lugar de escuchar cada clic en el DOM para ocultar un elemento específico, puede establecer tabindexel elemento primario <div>y escuchar los focusouteventos.

La configuración tabindexse asegurará de que el blurevento se active en <div>(normalmente no lo haría).

Entonces su HTML se vería así:

<div class="form_wrapper" tabindex="0">
    <a class="agree" href="javascript:;">I Agree</a>
    <a class="disagree" href="javascript:;">Disagree</a>
</div>

Y tu JS:

$('.form_wrapper').on('focusout', function(event){
    $('.form_wrapper').hide();
});
Oscar
fuente
5

Y para dispositivos táctiles como IPAD e IPHONE podemos usar el siguiente código

$(document).on('touchstart', function (event) {
var container = $("YOUR CONTAINER SELECTOR");

if (!container.is(e.target) // if the target of the click isn't the container...
&& container.has(e.target).length === 0) // ... nor a descendant of the container
    {
        container.hide();
    }
});
Code Spy
fuente
5

Aquí hay un jsfiddle que encontré en otro hilo, también funciona con la clave esc: http://jsfiddle.net/S5ftb/404

    var button = $('#open')[0]
    var el     = $('#test')[0]

    $(button).on('click', function(e) {
      $(el).show()
      e.stopPropagation()
    })

    $(document).on('click', function(e) {
      if ($(e.target).closest(el).length === 0) {
        $(el).hide()
      }
    })

    $(document).on('keydown', function(e) {
      if (e.keyCode === 27) {
        $(el).hide()
      }
    })
djv
fuente
Veo que detecta si el evento 'clic' está dentro del elemento #test ... intenté probar enlaces como jsfiddle.net/TA96A y parece que podrían funcionar.
Thomas W
Sí, parece que jsfiddle bloquea los enlaces externos. Si usa http: // jsfiddle.net verá que la página de resultados procesa el enlace :)
djv
5

Creado a partir de la increíble respuesta de prc322.

function hideContainerOnMouseClickOut(selector, callback) {
  var args = Array.prototype.slice.call(arguments); // Save/convert arguments to array since we won't be able to access these within .on()
  $(document).on("mouseup.clickOFF touchend.clickOFF", function (e) {
    var container = $(selector);

    if (!container.is(e.target) // if the target of the click isn't the container...
        && container.has(e.target).length === 0) // ... nor a descendant of the container
    {
      container.hide();
      $(document).off("mouseup.clickOFF touchend.clickOFF");
      if (callback) callback.apply(this, args);
    }
  });
}

Esto agrega un par de cosas ...

  1. Colocado dentro de una función con una devolución de llamada con argumentos "ilimitados"
  2. Se agregó una llamada a .off () de jquery emparejado con un espacio de nombres de eventos para desvincular el evento del documento una vez que se ha ejecutado.
  3. Touchend incluido para funcionalidad móvil

¡Espero que esto ayude a alguien!

WiseOlMan
fuente
4

Si tiene problemas con iOS, el mouseup no funciona en dispositivos Apple.

¿mousedown / mouseup en jquery funciona para el ipad?

yo uso esto:

$(document).bind('touchend', function(e) {
        var container = $("YOURCONTAINER");

          if (container.has(e.target).length === 0)
          {
              container.hide();
          }
      });
usuario2271066
fuente
4

(Solo agregando a la respuesta de prc322).

En mi caso, estoy usando este código para ocultar un menú de navegación que aparece cuando el usuario hace clic en la pestaña correspondiente. Descubrí que era útil agregar una condición adicional, que el objetivo del clic fuera del contenedor no es un enlace.

$(document).mouseup(function (e)
{
    var container = $("YOUR CONTAINER SELECTOR");

    if (!$("a").is(e.target) // if the target of the click isn't a link ...
        && !container.is(e.target) // ... or the container ...
        && container.has(e.target).length === 0) // ... or a descendant of the container
    {
        container.hide();
    }
});

Esto se debe a que algunos de los enlaces de mi sitio agregan contenido nuevo a la página. Si este nuevo contenido se agrega al mismo tiempo que desaparece el menú de navegación, puede ser desorientador para el usuario.

shngrdnr
fuente
4

Tantas respuestas, debe ser un derecho de paso para haber agregado una ... No vi una respuesta actual (jQuery 3.1.1), así que:

$(function() {
    $('body').on('mouseup', function() {
        $('#your-selector').hide();
    });
});
zak
fuente
3
var n = 0;
$("#container").mouseenter(function() {
n = 0;

}).mouseleave(function() {
n = 1;
});

$("html").click(function(){ 
if (n == 1) {
alert("clickoutside");
}
});
Gary
fuente
3
 $('body').click(function(event) {
    if (!$(event.target).is('p'))
    {
        $("#e2ma-menu").hide();
    }
});

pes el nombre del elemento Donde se puede pasar la identificación o clase o nombre del elemento también.

Abhishek
fuente
3

Devuelve falso si hace clic en .form_wrapper:

$('body').click(function() {
  $('.form_wrapper').click(function(){
  return false
});
   $('.form_wrapper').hide();
});

//$('.form_wrapper').click(function(event){
//   event.stopPropagation();
//});
bogo
fuente
3

Adjunte un evento de clic a elementos de nivel superior fuera del contenedor del formulario, por ejemplo:

$('#header, #content, #footer').click(function(){
    $('.form_wrapper').hide();
});

Esto también funcionará en dispositivos táctiles, solo asegúrese de no incluir un padre de .form_wrapper en su lista de selectores.

ThornberryPie
fuente
3

var exclude_div = $("#ExcludedDiv");;  
$(document).click(function(e){
   if( !exclude_div.is( e.target ) )  // if target div is not the one you want to exclude then add the class hidden
        $(".myDiv1").addClass("hidden");  

}); 

VIOLÍN

SharmaPattar
fuente
3

$(document).ready(function() {
	$('.modal-container').on('click', function(e) {
	  if(e.target == $(this)[0]) {
		$(this).removeClass('active'); // or hide()
	  }
	});
});
.modal-container {
	display: none;
	justify-content: center;
	align-items: center;
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	background-color: rgba(0,0,0,0.5);
	z-index: 999;
}

.modal-container.active {
    display: flex;  
}

.modal {
	width: 50%;
	height: auto;
	margin: 20px;
	padding: 20px;
	background-color: #fff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="modal-container active">
	<div class="modal">
		<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ac varius purus. Ut consectetur viverra nibh nec maximus. Nam luctus ligula quis arcu accumsan euismod. Pellentesque imperdiet volutpat mi et cursus. Sed consectetur sed tellus ut finibus. Suspendisse porttitor laoreet lobortis. Nam ut blandit metus, ut interdum purus.</p>
	</div>
</div>

MohoBarba
fuente
3

Copiado de https://sdtuts.com/click-on-not-specified-element/

Demostración en vivo http://demos.sdtuts.com/click-on-specified-element

$(document).ready(function () {
    var is_specified_clicked;
    $(".specified_element").click(function () {
        is_specified_clicked = true;
        setTimeout(function () {
            is_specified_clicked = false;
        }, 200);
    })
    $("*").click(function () {
        if (is_specified_clicked == true) {
//WRITE CODE HERE FOR CLICKED ON OTHER ELEMENTS
            $(".event_result").text("you were clicked on specified element");
        } else {
//WRITE CODE HERE FOR SPECIFIED ELEMENT CLICKED
            $(".event_result").text("you were clicked not on specified element");
        }
    })
})
usuario3151197
fuente
2

Lo hice así:

var close = true;

$(function () {

    $('body').click (function(){

        if(close){
            div.hide();
        }
        close = true;
    })


alleswasdenlayeronclicknichtschliessensoll.click( function () {   
        close = false;
    });

});
usuario2822517
fuente
2
dojo.query(document.body).connect('mouseup',function (e)
{
    var obj = dojo.position(dojo.query('div#divselector')[0]);
    if (!((e.clientX > obj.x && e.clientX <(obj.x+obj.w)) && (e.clientY > obj.y && e.clientY <(obj.y+obj.h))) ){
        MyDive.Hide(id);
    }
});
Abed Yaseen
fuente
2

Al usar este código, puede ocultar tantos elementos como desee

var boxArray = ["first element's id","second element's id","nth element's id"];
   window.addEventListener('mouseup', function(event){
   for(var i=0; i < boxArray.length; i++){
    var box = document.getElementById(boxArray[i]);
    if(event.target != box && event.target.parentNode != box){
        box.style.display = 'none';
    }
   }
})
Mahdi Younesi
fuente
1

Lo que puede hacer es vincular un evento de clic al documento que ocultará el menú desplegable si se hace clic en algo fuera del menú desplegable, pero no lo ocultará si se hace clic en algo dentro del menú desplegable, por lo que su evento "show" (o menú desplegable o lo que sea muestra el menú desplegable)

    $('.form_wrapper').show(function(){

        $(document).bind('click', function (e) {
            var clicked = $(e.target);
            if (!clicked.parents().hasClass("class-of-dropdown-container")) {
                 $('.form_wrapper').hide();
            }
        });

    });

Luego, al ocultarlo, desvincula el evento de clic

$(document).unbind('click');
jeffsaracco
fuente
0

Según los documentos , .blur()funciona para más que la <input>etiqueta. Por ejemplo:

$('.form_wrapper').blur(function(){
   $(this).hide();
});
Bizley
fuente
-1, no funciona. Idea muy interesante, pero los documentos de jQuery están equivocados. Consulte developer.mozilla.org/en-US/docs/Web/API/… , por ejemplo: "En contraste con MSIE, en el que casi todo tipo de elementos reciben el evento de desenfoque, casi todo tipo de elementos en los navegadores Gecko NO trabaje con este evento ". Además, probado en Chrome, y divnunca se difumina: los eventos de desenfoque ni siquiera pueden burbujearles de sus hijos. Finalmente, incluso si lo anterior no fuera cierto, esto solo funcionaría si se asegurara de que .form_wrapperestuviera enfocado antes de que el usuario lo apagara.
Mark Amery