Use o jQuery para ocultar um DIV quando o usuário clicar fora dele


967

Estou usando este código:

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

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

E este HTML :

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

O problema é que tenho links dentro dive quando eles não funcionam mais quando clicados.


6
Usando javascript simples que você pode tentar algo como isto: jsfiddle.net/aamir/y7mEY
Aamir Afridi

usando $('html')ou $(document)seria melhor que$('body')
Adrien Seja

Respostas:


2484

Teve o mesmo problema, veio com esta solução fácil. Até funciona recursivamente:

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

19
Basta colocá-lo no meu projeto, mas com um pequeno ajuste, usando uma matriz de elementos para percorrer todos eles de uma só vez. jsfiddle.net/LCB5W
Thomas

5
@mpelzsherman Muitas pessoas comentaram que o snippet funciona em dispositivos touch, mas desde que a postagem foi editada, esses comentários desapareceram um pouco. TBH Não sei se usei "mouseup" por um motivo específico, mas se ele também funciona com "click", não vejo razão para você não usar "click".

6
Eu precisava que o contêiner fosse oculto uma vez com esse evento, esse retorno de chamada deve ser destruído quando usado. Para fazer isso, usei o espaço para nome no evento click com bind ("click.namespace") e, quando o evento ocorreu, chamo unbind ("click.namespace"). E, finalmente, usei $ (e.target) .closest (". Container"). Length para reconhecer o container ... Portanto, não usei nenhum truque desta resposta: D
Loenix

80
Lembrando de usar $("YOUR CONTAINER SELECTOR").unbind( 'click', clickDocument );logo ao lado .hide(). Portanto document, não fique ouvindo cliques.
Brasofilo 12/10

12
Para práticas recomendadas, escrevi $(document).on("mouseup.hideDocClick", function () { ... });na função que abre o contêiner e $(document).off('.hideDocClick');na função ocultar. Usando espaços para nome, não estou removendo outros possíveis mouseupouvintes anexados ao documento.
campsjos

204

É melhor você ir com algo assim:

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();
    });
});

Que esperto! Esta técnica é padrão?
Advait

@ Advait Eu não vi isso usado antes. É tudo sobre o hovermanipulador de eventos, que abre muitas possibilidades.
Makram Saleh

5
Não considero que seja uma boa solução, pois permite que as pessoas pensem que é bom preencher o objeto de janela (= usando variáveis ​​globais).

1
Apenas para adicionar algo ao que o @ prc322 disse, você pode agrupar seu código com uma função anônima e chamar imediatamente. (function() { // ... code })(); Não me lembro do nome desse padrão, mas é super útil! Todas as suas variáveis ​​declaradas residirão dentro da função e não poluirão o espaço para nome global.
pedromanoel

3
@ prc322 Se você nem sabe como alterar o escopo de uma variável, está certo, esta solução não é boa para você ... e o JavaScript também não. Se você estiver apenas copiando e colando o código do Stack Overflow, terá muito mais problemas do que possivelmente substituindo algo no objeto da janela.
Gavin

87

Esse código detecta qualquer evento de clique na página e oculta o #CONTAINERelemento se e somente se o elemento clicado não era o #CONTAINERelemento nem um de seus descendentes.

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

Isto é perfeito!!
Mohd Abdul Mujib

@ 9KSoft Fico feliz em poder ajudá-lo. Obrigado pelo seu feedback e boa sorte.
Case

Esta solução funcionou perfeitamente para mim usando uma div como contêiner!
JCO9

76

Convém verificar o destino do evento click que é acionado para o corpo em vez de confiar em stopPropagation.

Algo como:

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

Além disso, o elemento body pode não incluir todo o espaço visual mostrado no navegador. Se você perceber que seus cliques não estão sendo registrados, talvez seja necessário adicionar o manipulador de cliques para o elemento HTML.


Sim, agora os links funcionam! Mas, por algum motivo, quando clico no link, ele é acionado duas vezes.
Scott Yu - constrói coisas

Acabei usando uma variação disso. Primeiro, verifico se o elemento está visível e se o target.hasClass eu o oculto.
Hawkee

E não se esqueça e.stopPropagation();, se você tem outro clique ouvinte
Darin Kolev

2
-1. Isso oculta form_wrapperquando você clica em um de seus filhos, que não é o comportamento desejado. Use a resposta do prc322.
Mark Amery

38

Demonstração ao vivo

Verificar se a área de clique não está no elemento de destino ou é filho

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

ATUALIZAR:

A propagação de parada do jQuery é a melhor solução

Demonstração ao vivo

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

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

$(document).click(function(){
    $(".dropdown").hide();
});

Obrigado pela atualização, perfeito! Funciona em dispositivos sensíveis ao toque?
FFish

1
No caso, você tem vários menus suspensos em uma página. Eu acho que você precisará fechar todos os menus suspensos antes de abrir clickedum. Caso contrário, stopPropagationisso tornaria possível que vários menus suspensos fossem abertos ao mesmo tempo.
T04435

19
$(document).click(function(event) {
    if ( !$(event.target).hasClass('form_wrapper')) {
         $(".form_wrapper").hide();
    }
});

2
Hmmm ... Se eu clicar em algo DENTRO da div, a div inteira desaparecerá por algum motivo.
Scott Yu - constrói coisas

11
Em vez de verificar se o destino tem a classe, tente: if ($ (event.target) .closest ('. Form_wrapper) .get (0) == null) {$ (". Form_wrapper"). Hide (); } Isso garantirá que clicar nas coisas dentro da div não oculte a div.
precisa saber é o seguinte

17

Atualizou a solução para:

  • use mouseenter e mouseleave
  • de pairar usar ligação ao evento ao 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');
    }
});

1
.liveagora está obsoleto ; use em .onvez disso.
Brett


9

Demonstração ao vivo com ESCfuncionalidade

Funciona em computadores e dispositivos móveis

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

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

Se, em algum caso, você precisar ter certeza de que seu elemento está realmente visível quando você clica no documento: if($pop.is(':visible') && (notH||e.which==27)) $pop.hide();


8

Algo assim não funcionaria?

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

});

ou

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

});

4
Esta resposta não está correta. Como muitas respostas aqui, isso oculta .form_wrapperquando você clica nos filhos (entre outros problemas).
Mark Amery

6

Mesmo sapatilha:

$("html").click(function(){ 
    $(".wrapper:visible").hide();
});

4
Esta resposta não está correta. Isso oculta o local .wrapperonde você clica na página, e não é o que foi solicitado.
Mark Amery

6

Em vez de ouvir cada clique no DOM para ocultar um elemento específico, você pode definir tabindexo pai <div>e ouvir os focusouteventos.

A configuração tabindexgarantirá que o blurevento seja disparado no <div>(normalmente não seria).

Portanto, seu HTML se pareceria com:

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

E seu JS:

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

5

E para dispositivos Touch como IPAD e IPHONE, podemos usar o seguinte 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();
    }
});

5

Aqui está um jsfiddle que encontrei em outro segmento, também funciona com a tecla 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()
      }
    })

Vejo que ele detecta se o evento 'click' está dentro do elemento #test. Tentei testar os links como jsfiddle.net/TA96A e parece que eles podem funcionar.
21413 Thomas Thomas W

Sim, parece que o jsfiddle bloqueia links externos. Se você usar http: // jsfiddle.net você verá a página de resultados processa o link :)
DJV

5

Construído a partir da resposta impressionante do 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);
    }
  });
}

Isso adiciona algumas coisas ...

  1. Colocado em uma função com retorno de chamada com argumentos "ilimitados"
  2. Adicionada uma chamada ao .off () do jquery emparelhado com um espaço para nome do evento para desvincular o evento do documento após a execução.
  3. Touchend incluído para funcionalidade móvel

Espero que isso ajude alguém!



4

(Apenas adicionando à resposta do prc322.)

No meu caso, estou usando esse código para ocultar um menu de navegação que aparece quando o usuário clica em uma guia apropriada. Achei útil adicionar uma condição extra, de que o alvo do clique fora do contêiner não é um link.

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

Isso ocorre porque alguns dos links do meu site adicionam novo conteúdo à página. Se esse novo conteúdo for adicionado ao mesmo tempo que o menu de navegação desaparecer, pode ser desorientador para o usuário.


4

Tantas respostas, deve ser um direito de passagem para ter adicionado uma ... Eu não vi respostas atuais (jQuery 3.1.1) - então:

$(function() {
    $('body').on('mouseup', function() {
        $('#your-selector').hide();
    });
});

3
var n = 0;
$("#container").mouseenter(function() {
n = 0;

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

$("html").click(function(){ 
if (n == 1) {
alert("clickoutside");
}
});

3
 $('body').click(function(event) {
    if (!$(event.target).is('p'))
    {
        $("#e2ma-menu").hide();
    }
});

pé o nome do elemento Onde se pode passar o ID ou o nome da classe ou do elemento também.


3

Retorne false se você clicar em .form_wrapper:

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

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

3

Anexe um evento click aos elementos de nível superior fora do wrapper de formulário, por exemplo:

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

Isso também funcionará em dispositivos sensíveis ao toque, mas não inclua um pai de .form_wrapper na sua lista de seletores.


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");  

}); 

FIDDLE


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>


3

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

Demonstração ao 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");
        }
    })
})

2

eu fiz assim:

var close = true;

$(function () {

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

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


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

});

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);
    }
});

2

Ao usar esse código, você pode ocultar quantos itens quiser

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';
    }
   }
})

1

O que você pode fazer é vincular um evento de clique ao documento que ocultará a lista suspensa se algo fora da lista suspensa for clicado, mas não a ocultará se algo dentro da lista suspensa for clicado. mostra a lista suspensa)

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

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

    });

Ao ocultá-lo, desvincule o evento click

$(document).unbind('click');

0

De acordo com os documentos , .blur()funciona para mais do que a <input>tag. Por exemplo:

$('.form_wrapper').blur(function(){
   $(this).hide();
});

-1, não funciona. Idéia muito interessante, mas os documentos do jQuery estão errados. Veja developer.mozilla.org/pt-BR/docs/Web/API/… , por exemplo: "Em contraste com o MSIE - no qual quase todos os tipos de elementos recebem o evento de desfoque - quase todos os tipos de elementos nos navegadores Gecko. NÃO trabalhe com este evento. " Além disso, testado no Chrome e divnunca desfocamos - os eventos de desfocagem nem podem ser refletidos pelos filhos. Por fim, mesmo que as opções acima não fossem verdadeiras, isso só funcionaria se você tivesse certeza de que .form_wrapperestava em foco antes de o usuário clicar nela.
Mark Amery
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.