ocultar hacer fuera evento este elemento div detectar clic javascript jquery

javascript - hacer - ¿Cómo detecto un clic fuera de un elemento?



ocultar div al hacer clic fuera de este javascript (30)

Tengo algunos menús HTML, que muestro completamente cuando un usuario hace clic en el encabezado de estos menús. Me gustaría ocultar estos elementos cuando el usuario haga clic fuera del área de los menús.

¿Es algo así posible con jQuery?

$("#menuscontainer").clickOutsideThisElement(function() { // Hide the menus });


¿Cómo detectar un clic fuera de un elemento?

La razón por la que esta pregunta es tan popular y tiene tantas respuestas es que es engañosamente compleja. Después de casi ocho años y docenas de respuestas, estoy realmente sorprendido de ver lo poco que se ha prestado atención a la accesibilidad.

Me gustaría ocultar estos elementos cuando el usuario haga clic fuera del área de los menús.

Esta es una causa noble y es el problema real . El título de la pregunta, que es lo que la mayoría de las respuestas parece tratar de abordar, contiene una desafortunada pista falsa.

Pista: es la palabra "click" !

En realidad, no desea enlazar controladores de clics.

Si está enlazando los controladores de clic para cerrar el cuadro de diálogo, ya ha fallado. La razón por la que has fallado es que no todos activan los eventos de click . Los usuarios que no utilicen un mouse podrán escapar de su cuadro de diálogo (y su menú emergente es posiblemente un tipo de diálogo) presionando la tecla Tab , y luego no podrán leer el contenido detrás del cuadro de diálogo sin disparar un click posteriormente evento.

Así que vamos a reformular la pregunta.

¿Cómo se cierra un diálogo cuando un usuario termina con él?

Este es el objetivo. Desafortunadamente, ahora debemos vincular al userisfinishedwiththedialog evento de userisfinishedwiththedialog , y ese enlace no es tan sencillo.

Entonces, ¿cómo podemos detectar que un usuario ha terminado de usar un diálogo?

evento de focusout

Un buen comienzo es determinar si el foco ha abandonado el diálogo.

Sugerencia: tenga cuidado con el evento de blur , el blur no se propaga si el evento estaba vinculado a la fase de propagación.

focusout jQuery hará bien. Si no puede usar jQuery, entonces puede usar blur durante la fase de captura:

element.addEventListener(''blur'', ..., true); // use capture: ^^^^

Además, para muchos cuadros de diálogo, deberá permitir que el contenedor se enfoque. Agregue tabindex="-1" para permitir que el cuadro de diálogo reciba un enfoque dinámico sin interrumpir el flujo de tabulación.

$(''a'').on(''click'', function () { $(this.hash).toggleClass(''active'').focus(); }); $(''div'').on(''focusout'', function () { $(this).removeClass(''active''); });

div { display: none; } .active { display: block; }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <a href="#example">Example</a> <div id="example" tabindex="-1"> Lorem ipsum <a href="http://example.com">dolor</a> sit amet. </div>

Si juegas con esa demo durante más de un minuto, deberías comenzar a ver rápidamente los problemas.

La primera es que el enlace en el diálogo no se puede hacer clic. Si intenta hacer clic en él o en la pestaña, se cerrará el cuadro de diálogo antes de que tenga lugar la interacción. Esto se debe a que enfocar el elemento interno activa un evento de focusout antes de focusin activar un evento de focusin .

La solución es poner en cola el cambio de estado en el bucle de eventos. Esto se puede hacer usando setImmediate(...) , o setTimeout(..., 0) para los navegadores que no admiten setImmediate . Una vez en cola, puede ser cancelado por un focusin subsiguiente:

$(''.submenu'').on({ focusout: function (e) { $(this).data(''submenuTimer'', setTimeout(function () { $(this).removeClass(''submenu--active''); }.bind(this), 0)); }, focusin: function (e) { clearTimeout($(this).data(''submenuTimer'')); } });

$(''a'').on(''click'', function () { $(this.hash).toggleClass(''active'').focus(); }); $(''div'').on({ focusout: function () { $(this).data(''timer'', setTimeout(function () { $(this).removeClass(''active''); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this).data(''timer'')); } });

div { display: none; } .active { display: block; }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <a href="#example">Example</a> <div id="example" tabindex="-1"> Lorem ipsum <a href="http://example.com">dolor</a> sit amet. </div>

El segundo problema es que el diálogo no se cerrará cuando se vuelva a presionar el enlace. Esto se debe a que el cuadro de diálogo pierde el enfoque, lo que desencadena el comportamiento de cierre, después de lo cual el clic del enlace activa el cuadro de diálogo para volver a abrir.

Al igual que en la edición anterior, el estado de enfoque debe ser administrado. Dado que el cambio de estado ya se ha puesto en cola, es solo una cuestión de manejar los eventos de enfoque en los activadores de diálogo:

Esto debería parecer familiar

$(''a'').on({ focusout: function () { $(this.hash).data(''timer'', setTimeout(function () { $(this.hash).removeClass(''active''); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this.hash).data(''timer'')); } });

$(''a'').on(''click'', function () { $(this.hash).toggleClass(''active'').focus(); }); $(''div'').on({ focusout: function () { $(this).data(''timer'', setTimeout(function () { $(this).removeClass(''active''); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this).data(''timer'')); } }); $(''a'').on({ focusout: function () { $(this.hash).data(''timer'', setTimeout(function () { $(this.hash).removeClass(''active''); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this.hash).data(''timer'')); } });

div { display: none; } .active { display: block; }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <a href="#example">Example</a> <div id="example" tabindex="-1"> Lorem ipsum <a href="http://example.com">dolor</a> sit amet. </div>

Tecla esc

Si creía que había terminado manejando los estados de enfoque, hay mucho más que puede hacer para simplificar la experiencia del usuario.

Esta es a menudo una característica "agradable de tener", pero es común que cuando tenga un modal o una ventana emergente de cualquier tipo, la tecla Esc la cerrará.

keydown: function (e) { if (e.which === 27) { $(this).removeClass(''active''); e.preventDefault(); } }

$(''a'').on(''click'', function () { $(this.hash).toggleClass(''active'').focus(); }); $(''div'').on({ focusout: function () { $(this).data(''timer'', setTimeout(function () { $(this).removeClass(''active''); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this).data(''timer'')); }, keydown: function (e) { if (e.which === 27) { $(this).removeClass(''active''); e.preventDefault(); } } }); $(''a'').on({ focusout: function () { $(this.hash).data(''timer'', setTimeout(function () { $(this.hash).removeClass(''active''); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this.hash).data(''timer'')); } });

div { display: none; } .active { display: block; }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <a href="#example">Example</a> <div id="example" tabindex="-1"> Lorem ipsum <a href="http://example.com">dolor</a> sit amet. </div>

Si sabe que tiene elementos enfocados dentro del diálogo, no necesitará enfocar el diálogo directamente. Si está creando un menú, podría enfocar el primer elemento del menú.

click: function (e) { $(this.hash) .toggleClass(''submenu--active'') .find(''a:first'') .focus(); e.preventDefault(); }

$(''.menu__link'').on({ click: function (e) { $(this.hash) .toggleClass(''submenu--active'') .find(''a:first'') .focus(); e.preventDefault(); }, focusout: function () { $(this.hash).data(''submenuTimer'', setTimeout(function () { $(this.hash).removeClass(''submenu--active''); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this.hash).data(''submenuTimer'')); } }); $(''.submenu'').on({ focusout: function () { $(this).data(''submenuTimer'', setTimeout(function () { $(this).removeClass(''submenu--active''); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this).data(''submenuTimer'')); }, keydown: function (e) { if (e.which === 27) { $(this).removeClass(''submenu--active''); e.preventDefault(); } } });

.menu { list-style: none; margin: 0; padding: 0; } .menu:after { clear: both; content: ''''; display: table; } .menu__item { float: left; position: relative; } .menu__link { background-color: lightblue; color: black; display: block; padding: 0.5em 1em; text-decoration: none; } .menu__link:hover, .menu__link:focus { background-color: black; color: lightblue; } .submenu { border: 1px solid black; display: none; left: 0; list-style: none; margin: 0; padding: 0; position: absolute; top: 100%; } .submenu--active { display: block; } .submenu__item { width: 150px; } .submenu__link { background-color: lightblue; color: black; display: block; padding: 0.5em 1em; text-decoration: none; } .submenu__link:hover, .submenu__link:focus { background-color: black; color: lightblue; }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <ul class="menu"> <li class="menu__item"> <a class="menu__link" href="#menu-1">Menu 1</a> <ul class="submenu" id="menu-1" tabindex="-1"> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#1">Example 1</a></li> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#2">Example 2</a></li> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#3">Example 3</a></li> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#4">Example 4</a></li> </ul> </li> <li class="menu__item"> <a class="menu__link" href="#menu-2">Menu 2</a> <ul class="submenu" id="menu-2" tabindex="-1"> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#1">Example 1</a></li> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#2">Example 2</a></li> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#3">Example 3</a></li> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#4">Example 4</a></li> </ul> </li> </ul> lorem ipsum <a href="http://example.com/">dolor</a> sit amet.

Funciones de WAI-ARIA y otro soporte de accesibilidad

Esperamos que esta respuesta cubra los aspectos básicos de la compatibilidad con el teclado y el mouse accesibles para esta función, pero como ya es bastante importante, evitaré cualquier discusión sobre los roles y atributos de WAI-ARIA. en qué roles deben usar y cualquier otro atributo apropiado.


NOTA: El uso de stopEventPropagation() es algo que se debe evitar ya que interrumpe el flujo de eventos normal en el DOM. Vea este artículo para más información. Considere usar este método en su lugar.

Adjunte un evento de clic al cuerpo del documento que cierra la ventana. Adjunte un evento de clic separado al contenedor que detiene la propagación al cuerpo del documento.

$(window).click(function() { //Hide the menus if visible }); $(''#menucontainer'').click(function(event){ event.stopPropagation(); });


Solución 1

En lugar de usar event.stopPropagation () que puede tener algunos efectos secundarios, simplemente defina una variable de marca simple y agregue una condición if . Probé esto y funcioné correctamente sin ningún efecto secundario de stopPropagation:

var flag = "1"; $(''#menucontainer'').click(function(event){ flag = "0"; // flag 0 means click happened in the area where we should not do any action }); $(''html'').click(function() { if(flag != "0"){ // Hide the menus if visible } else { flag = "1"; } });

Solución 2

Con sólo una simple condición:

$(document).on(''click'', function(event){ var container = $("#menucontainer"); if (!container.is(event.target) && // If the target of the click isn''t the container... container.has(event.target).length === 0) // ... nor a descendant of the container { // Do whatever you want to do when click is outside the element } });


¡Esto me funcionó perfectamente!

$(''html'').click(function (e) { if (e.target.id == ''YOUR-DIV-ID'') { //do something } else { //do something } });


Ahora hay un complemento para eso: eventos externos ( publicación de blog )

Lo siguiente sucede cuando un controlador de clickoutside (WLOG) está vinculado a un elemento:

  • el elemento se agrega a una matriz que contiene todos los elementos con controladores de clickoutside
  • un controlador de clic ( namespaced ) está vinculado al documento (si no está ya allí)
  • en cualquier clic en el documento, el evento clickoutside se activa para aquellos elementos en esa matriz que no son iguales o un elemento primario del objetivo click -events
  • adicionalmente, el evento.target para el evento clickoutside se establece en el elemento en el que el usuario hizo clic (por lo que incluso sabe en qué hizo clic el usuario, no solo que hizo clic fuera)

Por lo tanto, no se detiene la propagación de eventos y se pueden usar controladores de clic adicionales "arriba" del elemento con el controlador externo.


Aquí está la solución de JavaScript de vainilla para futuros espectadores.

Al hacer clic en cualquier elemento dentro del documento, si la identificación del elemento en el que se hizo clic está alternada, o si el elemento oculto no está oculto y el elemento oculto no contiene el elemento, haga clic en el elemento.

(function () { "use strict"; var hidden = document.getElementById(''hidden''); document.addEventListener(''click'', function (e) { if (e.target.id == ''toggle'' || (hidden.style.display != ''none'' && !hidden.contains(e.target))) hidden.style.display = hidden.style.display == ''none'' ? ''block'' : ''none''; }, false); })();

(function () { "use strict"; var hidden = document.getElementById(''hidden''); document.addEventListener(''click'', function (e) { if (e.target.id == ''toggle'' || (hidden.style.display != ''none'' && !hidden.contains(e.target))) hidden.style.display = hidden.style.display == ''none'' ? ''block'' : ''none''; }, false); })();

<a href="javascript:void(0)" id="toggle">Toggle Hidden Div</a> <div id="hidden" style="display: none;">This content is normally hidden. click anywhere other than this content to make me disappear</div>

Si va a tener varias opciones en la misma página, puede usar algo como esto:

  1. Agregue el nombre de la clase hidden al elemento plegable.
  2. Al hacer clic en el documento, cierre todos los elementos ocultos que no contengan el elemento pulsado y no estén ocultos
  3. Si el elemento pulsado es un conmutador, alterne el elemento especificado.

(function () { "use strict"; var hiddenItems = document.getElementsByClassName(''hidden''), hidden; document.addEventListener(''click'', function (e) { for (var i = 0; hidden = hiddenItems[i]; i++) { if (!hidden.contains(e.target) && hidden.style.display != ''none'') hidden.style.display = ''none''; } if (e.target.getAttribute(''data-toggle'')) { var toggle = document.querySelector(e.target.getAttribute(''data-toggle'')); toggle.style.display = toggle.style.display == ''none'' ? ''block'' : ''none''; } }, false); })();

<a href="javascript:void(0)" data-toggle="#hidden1">Toggle Hidden Div</a> <div class="hidden" id="hidden1" style="display: none;" data-hidden="true">This content is normally hidden</div> <a href="javascript:void(0)" data-toggle="#hidden2">Toggle Hidden Div</a> <div class="hidden" id="hidden2" style="display: none;" data-hidden="true">This content is normally hidden</div> <a href="javascript:void(0)" data-toggle="#hidden3">Toggle Hidden Div</a> <div class="hidden" id="hidden3" style="display: none;" data-hidden="true">This content is normally hidden</div>


Como dijo otro póster, hay muchos errores, especialmente si el elemento que está mostrando (en este caso, un menú) tiene elementos interactivos. He encontrado que el siguiente método es bastante robusto:

$(''#menuscontainer'').click(function(event) { //your code that shows the menus fully //now set up an event listener so that clicking anywhere outside will close the menu $(''html'').click(function(event) { //check up the tree of the click target to check whether user has clicked outside of menu if ($(event.target).parents(''#menuscontainer'').length==0) { // your code to hide menu //this event listener has done its job so we can unbind it. $(this).unbind(event); } }) });


Como variante:

var $menu = $(''#menucontainer''); $(document).on(''click'', function (e) { // If element is opened and click target is outside it, hide it if ($menu.is('':visible'') && !$menu.is(e.target) && !$menu.has(e.target).length) { $menu.hide(); } });

No tiene problemas para css-tricks.com/dangers-stopping-event-propagation y es mejor admitir varios menús en la misma página donde hacer clic en un segundo menú mientras el primero está abierto dejará el primero abierto en la solución stopPropagation.


Después de la investigación, he encontrado tres soluciones que funcionan (olvidé los enlaces de la página como referencia)

Primera solucion

<script> //The good thing about this solution is it doesn''t stop event propagation. var clickFlag = 0; $(''body'').on(''click'', function () { if(clickFlag == 0) { console.log(''hide element here''); /* Hide element here */ } else { clickFlag=0; } }); $(''body'').on(''click'',''#testDiv'', function (event) { clickFlag = 1; console.log(''showed the element''); /* Show the element */ }); </script>

Segunda solucion

<script> $(''body'').on(''click'', function(e) { if($(e.target).closest(''#testDiv'').length == 0) { /* Hide dropdown here */ } }); </script>

Tercera solucion

<script> var specifiedElement = document.getElementById(''testDiv''); document.addEventListener(''click'', function(event) { var isClickInside = specifiedElement.contains(event.target); if (isClickInside) { console.log(''You clicked inside'') } else { console.log(''You clicked outside'') } }); </script>


Encontré este método en algún plugin de calendario jQuery.

function ClickOutsideCheck(e) { var el = e.target; var popup = $(''.popup:visible'')[0]; if (popup==undefined) return true; while (true){ if (el == popup ) { return true; } else if (el == document) { $(".popup").hide(); return false; } else { el = $(el).parent()[0]; } } }; $(document).bind(''mousedown.popup'', ClickOutsideCheck);


Función:

$(function() { $.fn.click_inout = function(clickin_handler, clickout_handler) { var item = this; var is_me = false; item.click(function(event) { clickin_handler(event); is_me = true; }); $(document).click(function(event) { if (is_me) { is_me = false; } else { clickout_handler(event); } }); return this; } });

Uso:

this.input = $(''<input>'') .click_inout( function(event) { me.ShowTree(event); }, function() { me.Hide(); } ) .appendTo(this.node);

Y las funciones son muy simples:

ShowTree: function(event) { this.data_span.show(); } Hide: function() { this.data_span.hide(); }


He tenido éxito con algo como esto:

var $menuscontainer = ...; $(''#trigger'').click(function() { $menuscontainer.show(); $(''body'').click(function(event) { var $target = $(event.target); if ($target.parents(''#menuscontainer'').length == 0) { $menuscontainer.hide(); } }); });

La lógica es: cuando se muestra #menuscontainer , vincule un controlador de clic al cuerpo que oculta #menuscontainer solo si el objetivo (del clic) no es hijo de él.


Las otras soluciones aquí no funcionaron para mí, así que tuve que usar:

if(!$(event.target).is(''#foo'')) { // hide menu }


No creo que lo que realmente necesite es cerrar el menú cuando el usuario haga clic fuera; lo que necesita es que el menú se cierre cuando el usuario haga clic en cualquier lugar de la página. Si hace clic en el menú, o fuera del menú, debería cerrarse, ¿verdad?

Al no encontrar respuestas satisfactorias en el párrafo anterior, tuve que escribir este blog el otro día. Para los más pedantes, hay una serie de errores para tomar nota de:

  1. Si adjunta un controlador de eventos de clic al elemento del cuerpo en el momento del clic, asegúrese de esperar el segundo clic antes de cerrar el menú y de desenlazar el evento. De lo contrario, el evento de clic que abrió el menú aumentará hasta el oyente que tiene que cerrar el menú.
  2. Si usa event.stopPropogation () en un evento de clic, ningún otro elemento de su página puede tener una función de clic en cualquier lugar para cerrar.
  3. Adjuntar un controlador de eventos de clic al elemento del cuerpo de forma indefinida no es una solución eficaz
  4. Al comparar el objetivo del evento y sus padres con el creador del controlador, se supone que lo que desea es cerrar el menú al hacer clic en él, cuando lo que realmente desea es cerrarlo cuando hace clic en cualquier lugar de la página.
  5. Escuchar eventos en el elemento del cuerpo hará que su código sea más frágil. Un estilo tan inocente como esto lo rompería: body { margin-left:auto; margin-right: auto; width:960px;} body { margin-left:auto; margin-right: auto; width:960px;}

Puede escuchar un evento de clic en el document y luego asegurarse de que #menucontainer no sea un antepasado o el objetivo del elemento pulsado utilizando .closest() .

Si no lo está, entonces el elemento pulsado está fuera del #menucontainer y puede ocultarlo de forma segura.

$(document).click(function(event) { if(!$(event.target).closest(''#menucontainer'').length) { if($(''#menucontainer'').is(":visible")) { $(''#menucontainer'').hide(); } } });

Editar - 2017-06-23

También puede limpiar después del detector de eventos si planea descartar el menú y desea dejar de escuchar eventos. Esta función limpiará solo el oyente recién creado, conservando cualquier otro oyente de clic en el document . Con la sintaxis ES2015:

export function hideOnClickOutside(selector) { const outsideClickListener = (event) => { if (!$(event.target).closest(selector).length) { if ($(selector).is('':visible'')) { $(selector).hide() removeClickListener() } } } const removeClickListener = () => { document.removeEventListener(''click'', outsideClickListener) } document.addEventListener(''click'', outsideClickListener) }

Editar - 2018-03-11

Para aquellos que no quieren usar jQuery. Aquí está el código de arriba en vanillaJS (ECMAScript6).

function hideOnClickOutside(element) { const outsideClickListener = event => { if (!element.contains(event.target)) { // or use: event.target.closest(selector) === null if (isVisible(element)) { element.style.display = ''none'' removeClickListener() } } } const removeClickListener = () => { document.removeEventListener(''click'', outsideClickListener) } document.addEventListener(''click'', outsideClickListener) } const isVisible = elem => !!elem && !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ) // source (2018-03-11): https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js

NOTA: Esto se basa en el comentario de Alex para usar simplemente !element.contains(event.target) lugar de la parte jQuery.

Pero element.closest() ahora también está disponible en todos los navegadores principales (la versión W3C difiere un poco de la jQuery). Polyfills se puede encontrar aquí: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest


Tengo una aplicación que funciona de manera similar al ejemplo de Eran, excepto que adjunto el evento click al cuerpo cuando abro el menú ... Un poco como esto:

$(''#menucontainer'').click(function(event) { $(''html'').one(''click'',function() { // Hide the menus }); event.stopPropagation(); });

Más información sobre la función one() jQuery one()


Una solución simple para la situación es:

$(document).mouseup(function (e) { var container = $("YOUR SELECTOR"); // Give you class or ID if (!container.is(e.target) && // If the target of the click is not the desired div or section container.has(e.target).length === 0) // ... nor a descendant-child of the container { container.hide(); } });

La secuencia de comandos anterior ocultará el div si se desencadena el evento div click.

Puede ver el siguiente blog para obtener más información: http://www.codecanal.com/detect-click-outside-div-using-javascript/


Utilizar:

var go = false; $(document).click(function(){ if(go){ $(''#divID'').hide(); go = false; } }) $("#divID").mouseover(function(){ go = false; }); $("#divID").mouseout(function (){ go = true; }); $("btnID").click( function(){ if($("#divID:visible").length==1) $("#divID").hide(); // Toggle $("#divID").show(); });


Verifique el destino del evento de clic en la ventana (debe propagarse a la ventana, siempre que no se capture en ningún otro lugar), y asegúrese de que no sea ninguno de los elementos del menú. Si no lo es, entonces estás fuera de tu menú.

O verifique la posición del clic y vea si está dentro del área del menú.


En lugar de usar la interrupción del flujo, el evento de desenfoque / enfoque o cualquier otra técnica delicada, simplemente haga coincidir el flujo del evento con el parentesco del elemento:

$(document).on("click.menu-outside", function(event){ // Test if target and it''s parent aren''t #menuscontainer // That means the click event occur on other branch of document tree if(!$(event.target).parents().andSelf().is("#menuscontainer")){ // Click outisde #menuscontainer // Hide the menus (but test if menus aren''t already hidden) } });

Para eliminar, haga clic fuera del detector de eventos, simplemente:

$(document).off("click.menu-outside");


Esta es mi solución a este problema:

$(document).ready(function() { $(''#user-toggle'').click(function(e) { $(''#user-nav'').toggle(); e.stopPropagation(); }); $(''body'').click(function() { $(''#user-nav'').hide(); }); $(''#user-nav'').click(function(e){ e.stopPropagation(); }); });


Para un uso más sencillo y un código más expresivo, creé un complemento de jQuery para esto:

$(''div.my-element'').clickOut(function(target) { //do something here... });

Nota: target es el elemento que el usuario realmente hizo clic. Pero la devolución de llamada aún se ejecuta en el contexto del elemento original, por lo que puede utilizar esto como se esperaría en una devolución de llamada jQuery.

Enchufar:

$.fn.clickOut = function (parent, fn) { var context = this; fn = (typeof parent === ''function'') ? parent : fn; parent = (parent instanceof jQuery) ? parent : $(document); context.each(function () { var that = this; parent.on(''click'', function (e) { var clicked = $(e.target); if (!clicked.is(that) && !clicked.parents().is(that)) { if (typeof fn === ''function'') { fn.call(that, clicked); } } }); }); return context; };

De forma predeterminada, el detector de eventos de clic se coloca en el documento. Sin embargo, si desea limitar el alcance del detector de eventos, puede pasar un objeto jQuery que represente un elemento de nivel primario que será el principal superior al que se escucharán los clics. Esto evita escuchas de eventos de nivel de documento innecesario. Obviamente, no funcionará a menos que el elemento padre provisto sea un padre de su elemento inicial.

Utilizar como tal:

$(''div.my-element'').clickOut($(''div.my-parent''), function(target) { //do something here... });


Si está ejecutando scripts para IE y FF 3. * y solo desea saber si el clic se produjo dentro de un área de cuadro determinada, también podría usar algo como:

this.outsideElementClick = function(objEvent, objElement){ var objCurrentElement = objEvent.target || objEvent.srcElement; var blnInsideX = false; var blnInsideY = false; if (objCurrentElement.getBoundingClientRect().left >= objElement.getBoundingClientRect().left && objCurrentElement.getBoundingClientRect().right <= objElement.getBoundingClientRect().right) blnInsideX = true; if (objCurrentElement.getBoundingClientRect().top >= objElement.getBoundingClientRect().top && objCurrentElement.getBoundingClientRect().bottom <= objElement.getBoundingClientRect().bottom) blnInsideY = true; if (blnInsideX && blnInsideY) return false; else return true;}


Terminé haciendo algo como esto:

$(document).on(''click'', ''body, #msg_count_results .close'',function() { $(document).find(''#msg_count_results'').remove(); }); $(document).on(''click'',''#msg_count_results'',function(e) { e.preventDefault(); return false; });

Tengo un botón de cierre dentro del nuevo contenedor para fines de la interfaz de usuario amigable para los usuarios finales. Tuve que usar return false para no pasar. Por supuesto, tener un A HREF allí para llevarte a algún lugar sería bueno, o podrías llamar a algunas cosas del ajax en su lugar. De cualquier manera, funciona bien para mí. Justo lo que quería.


Upvote para la respuesta más popular, pero agrega

&& (e.target != $(''html'').get(0)) // ignore the scrollbar

por lo tanto, un clic en una barra de desplazamiento no [esconde o lo que sea] su elemento objetivo.


El evento tiene una propiedad llamada event.path del elemento que es una "lista estática ordenada de todos sus ancestros en orden de árbol" . Para verificar si un evento se originó desde un elemento DOM específico o uno de sus hijos, simplemente verifique la ruta para ese elemento DOM específico. También se puede usar para verificar múltiples elementos al ingresar lógicamente ORla verificación de elementos en la somefunción.

$("body").click(function() { target = document.getElementById("main"); flag = event.path.some(function(el, i, arr) { return (el == target) }) if (flag) { console.log("Inside") } else { console.log("Outside") } });

#main { display: inline-block; }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="main"> <ul> <li>Test-Main</li> <li>Test-Main</li> <li>Test-Main</li> <li>Test-Main</li> <li>Test-Main</li> </ul> </div> <div id="main2"> Outside Main </div>

Así que para tu caso debería ser

$("body").click(function() { target = $("#menuscontainer")[0]; flag = event.path.some(function(el, i, arr) { return (el == target) }); if (!flag) { // Hide the menus } });


Enganche un detector de eventos de clic en el documento. Dentro de la escucha de eventos, puede mirar el objeto de evento , en particular, event.target para ver en qué elemento se hizo clic:

$(document).click(function(e){ if ($(e.target).closest("#menuscontainer").length == 0) { // .closest can help you determine if the element // or one of its ancestors is #menuscontainer console.log("hide"); } });


Implementamos una solución, en parte basada en un comentario de un usuario anterior, que funciona perfectamente para nosotros. Lo usamos para ocultar un cuadro de búsqueda / resultados al hacer clic fuera de esos elementos, excluyendo el elemento que originalmente.

// HIDE SEARCH BOX IF CLICKING OUTSIDE $(document).click(function(event){ // IF NOT CLICKING THE SEARCH BOX OR ITS CONTENTS OR SEARCH ICON if ($("#search-holder").is(":visible") && !$(event.target).is("#search-holder *, #search")) { $("#search-holder").fadeOut(''fast''); $("#search").removeClass(''active''); } });

También verifica si el cuadro de búsqueda también es visible primero, y en nuestro caso, también está eliminando una clase activa en el botón de búsqueda de ocultar / mostrar.


$("#menuscontainer").click(function() { $(this).focus(); }); $("#menuscontainer").blur(function(){ $(this).hide(); });

Funciona para mí muy bien.


$(document).click(function() { $(".overlay-window").hide(); }); $(".overlay-window").click(function() { return false; });

Si hace clic en el documento, oculte un elemento dado, a menos que haga clic en ese mismo elemento.