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.

Scott Yu - constrói coisas
fonte
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();
    }
});

fonte
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();
    });
});
Makram Saleh
fonte
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();
    }
});
Caso
fonte
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.

David Andres
fonte
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();
});
MaxEcho
fonte
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();
    }
});
meder omuraliev
fonte
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');
    }
});
benvds
fonte
1
.liveagora está obsoleto ; use em .onvez disso.
Brett
15

Uma solução sem jQuery para a resposta mais popular :

document.addEventListener('mouseup', function (e) {
    var container = document.getElementById('your container ID');

    if (!container.contains(e.target)) {
        container.style.display = 'none';
    }
}.bind(this));

MDN: https://developer.mozilla.org/en/docs/Web/API/Node/contains

Martin Vseticka
fonte
bindnão funciona. Você poderia consertar a função para fazê-la funcionar?
Memmo
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();

Roko C. Buljan
fonte
8

Algo assim não funcionaria?

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

});

ou

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

});
MRVDOG
fonte
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();
});
Olivenbaum
fonte
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();
});
Oscar
fonte
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();
    }
});
Code Spy
fonte
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()
      }
    })
djv
fonte
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!

WiseOlMan
fonte
4

se você tiver problemas com o ios, o mouseup não está funcionando no dispositivo apple.

mousedown / mouseup no jquery funciona para o ipad?

Eu uso isso:

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

          if (container.has(e.target).length === 0)
          {
              container.hide();
          }
      });
user2271066
fonte
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.

shngrdnr
fonte
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();
    });
});
zak
fonte
3
var n = 0;
$("#container").mouseenter(function() {
n = 0;

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

$("html").click(function(){ 
if (n == 1) {
alert("clickoutside");
}
});
Gary
fonte
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.

Abhishek
fonte
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();
//});
bogo
fonte
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.

ThornberryPie
fonte
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

SharmaPattar
fonte
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>

RustBeard
fonte
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");
        }
    })
})
user3151197
fonte
2

eu fiz assim:

var close = true;

$(function () {

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

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


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

});
user2822517
fonte
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
fonte
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';
    }
   }
})
Mahdi Younesi
fonte
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');
jeffsaracco
fonte
0

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

$('.form_wrapper').blur(function(){
   $(this).hide();
});
Bizley
fonte
-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