Utilizzare jQuery per nascondere un DIV quando l'utente fa clic all'esterno di esso


968

Sto usando questo codice:

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

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

E questo HTML :

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

Il problema è che ho link all'interno dive quando non funzionano più quando si fa clic.


6
Usando javascript semplice puoi provare qualcosa del genere: jsfiddle.net/aamir/y7mEY
Aamir Afridi

usando $('html')o $(document)sarebbe meglio di$('body')
Adrien Be

Risposte:


2484

Ho avuto lo stesso problema, ho trovato questa soluzione semplice. Funziona anche in modo ricorsivo:

$(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
Inseriscilo nel mio progetto, ma con una piccola modifica, usando una serie di elementi per farli scorrere tutti in una volta. jsfiddle.net/LCB5W
Thomas il

5
@mpelzsherman Molte persone hanno commentato che lo snippet funziona su dispositivi touch ma da quando il post è stato modificato questi commenti sono in qualche modo svaniti. TBH Non so se ho usato "mouseup" per un motivo specifico, ma se funziona anche con "click" non vedo alcun motivo per cui non dovresti usare "click".

6
Avevo bisogno che il contenitore fosse nascosto una volta con questo evento, questo callback dovrebbe essere distrutto quando usato. Per fare ciò, ho usato lo spazio dei nomi sull'evento click con bind ("click.namespace") e quando si è verificato l'evento, chiamo unbind ("click.namespace"). E infine, ho usato $ (e.target) .closest (". Container"). Lunghezza per riconoscere il container ... Quindi, non ho usato alcun trucco da questa risposta: D
Loenix

80
Ricordando di usare $("YOUR CONTAINER SELECTOR").unbind( 'click', clickDocument );proprio accanto .hide(). Quindi documentnon continuare ad ascoltare i clic.
brasofilo,

12
Per le migliori pratiche che avevo scritto $(document).on("mouseup.hideDocClick", function () { ... });nella funzione che apre il contenitore e $(document).off('.hideDocClick');nella funzione Nascondi. Usando gli spazi dei nomi non sto rimuovendo altri possibili mouseupascoltatori allegati al documento.
Campsjos,

204

Faresti meglio ad andare con qualcosa del genere:

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

Che bravo! Questa tecnica è standard?
Adotta il

@advait Non l'avevo mai visto usato prima. Riguarda il hovergestore di eventi, che apre molte possibilità.
Makram Saleh,

5
Non ritengo che questa sia una buona soluzione poiché consente alle persone di pensare che sia giusto popolare l'oggetto window (= usando variabili globali).

1
Solo per aggiungere qualcosa a ciò che ha detto @ prc322, puoi racchiudere il tuo codice con una funzione anonima e farlo chiamare immediatamente. (function() { // ... code })(); Non ricordo il nome di questo modello, ma è super utile! Tutte le variabili dichiarate risiederanno all'interno della funzione e non inquineranno lo spazio dei nomi globale.
Pedromanoel,

3
@ prc322 Se non sai nemmeno come modificare l'ambito di una variabile, allora hai ragione, questa soluzione non è adatta a te ... e nemmeno JavaScript. Se stai solo copiando e incollando il codice da Stack Overflow, avrai molti più problemi che probabilmente sovrascrivere qualcosa nell'oggetto window.
Gavin,

87

Questo codice rileva qualsiasi evento click sulla pagina e quindi nasconde l' #CONTAINERelemento se e solo se l'elemento cliccato non era né l' #CONTAINERelemento né uno dei suoi discendenti.

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

Questo è perfetto!!
Mohd Abdul Mujib,

@ 9KSoft Sono contento che sia stato in grado di aiutarti. Grazie per il tuo feedback e buona fortuna.
Caso

Questa soluzione ha funzionato perfettamente per me usando un div come contenitore!
JCO9,

76

Potresti voler controllare la destinazione dell'evento click che si attiva per il corpo invece di fare affidamento su stopPropagation.

Qualcosa di simile a:

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

Inoltre, l'elemento body potrebbe non includere l'intero spazio visivo mostrato nel browser. Se noti che i tuoi clic non si stanno registrando, potrebbe essere necessario aggiungere invece il gestore di clic per l'elemento HTML.


Sì, ora i collegamenti funzionano! Ma per qualche motivo, quando faccio clic sul collegamento, viene attivato due volte.
Scott Yu - costruisce cose il

Ho finito per usare una variante di questo. Per prima cosa controllo se l'elemento è visibile, quindi se target.hasClass lo nascondo.
Hawkee,

e non dimenticare e.stopPropagation();se hai altri ascoltatori di clic
Darin Kolev,

2
-1. Questo nasconde form_wrapperquando si fa clic su uno dei suoi figli, che non è il comportamento desiderato. Utilizzare invece la risposta di prc322.
Mark Amery,

38

Dimostrazione dal vivo

Verifica che l'area dei clic non sia nell'elemento target o nella sua sezione figlio

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

AGGIORNARE:

jQuery stop propagation è la soluzione migliore

Dimostrazione dal vivo

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

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

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

Grazie per l'aggiornamento, perfetto! Funziona su dispositivi touch?
Pesci

1
Nel caso, hai più menu a discesa su una pagina. Penso che dovrai chiudere tutti i menu a discesa prima di aprire clickedquello. Altrimenti, stopPropagationrenderebbe possibile l'apertura di più menu a discesa contemporaneamente.
T04435

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

2
Hmmm ... Se clicco su qualcosa DENTRO il div, l'intero div scompare per qualche motivo.
Scott Yu - costruisce cose il

11
Invece di verificare se il target ha la classe, prova: if ($ (event.target) .closest ('. Form_wrapper) .get (0) == null) {$ (". Form_wrapper"). Hide (); } Questo assicurerà che facendo clic sulle cose all'interno del div non si nasconda il div.
John Haager,

17

Aggiornato la soluzione a:

  • usa invece mouseenter e mouseleave
  • di hover usa l'associazione di eventi live

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
.liveè ora obsoleto ; usa .oninvece.
Brett,


9

Demo live con ESCfunzionalità

Funziona sia su desktop che su dispositivo mobile

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

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

Se per alcuni casi devi essere sicuro che il tuo elemento sia davvero visibile quando fai clic sul documento: if($pop.is(':visible') && (notH||e.which==27)) $pop.hide();


8

Qualcosa del genere non funzionerebbe?

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

});

o

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

});

4
Questa risposta non è corretta Come molte risposte qui, questo nasconderà il .form_wrapperclic sui suoi figli (tra gli altri problemi).
Mark Amery,

6

Anche sleaker:

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

4
Questa risposta non è corretta Ciò nasconderà la .wrapperquestione indipendentemente da dove si fa clic sulla pagina, che non è ciò che è stato richiesto.
Mark Amery,

6

Invece di ascoltare ogni singolo clic sul DOM per nascondere un elemento specifico, è possibile impostare tabindexil genitore <div>e ascoltarefocusout eventi.

L'impostazione tabindexassicurerà che l' blurevento venga generato sul<div> (normalmente non lo farebbe).

Quindi il tuo HTML sarebbe simile a:

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

E il tuo JS:

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

5

E per dispositivi Touch come IPAD e IPHONE possiamo usare il seguente codice

$(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

Ecco un jsfiddle che ho trovato su un altro thread, funziona anche con il tasto 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()
      }
    })

Vedo che rileva se l'evento "click" è all'interno dell'elemento #test. Ho provato a inserire i collegamenti come jsfiddle.net/TA96A e sembra che potrebbero funzionare.
Thomas W,

Sì, sembra che jsfiddle blocchi i collegamenti esterni. Se usi http: // jsfiddle.net vedrai che la pagina dei risultati elabora il link :)
djv

5

Costruito sulla fantastica risposta di 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);
    }
  });
}

Questo aggiunge un paio di cose ...

  1. Inserito in una funzione con un callback con argomenti "illimitati"
  2. Aggiunta una chiamata al .off () di jquery associato a uno spazio dei nomi di evento per separare l'evento dal documento una volta eseguito.
  3. Touchend incluso per funzionalità mobile

Spero che questo aiuti qualcuno!



4

(Basta aggiungere alla risposta di prc322.)

Nel mio caso sto usando questo codice per nascondere un menu di navigazione che appare quando l'utente fa clic su una scheda appropriata. Ho trovato utile aggiungere una condizione aggiuntiva, che la destinazione del clic all'esterno del contenitore non è un collegamento.

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

Questo perché alcuni dei collegamenti sul mio sito aggiungono nuovi contenuti alla pagina. Se questo nuovo contenuto viene aggiunto contemporaneamente alla scomparsa del menu di navigazione, potrebbe essere disorientante per l'utente.


4

Così tante risposte, deve essere un diritto di passaggio per averne aggiunto uno ... Non ho visto le risposte attuali (jQuery 3.1.1) - quindi:

$(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è il nome dell'elemento. Dove si può passare anche l'id o la classe o il nome dell'elemento.


3

Restituisce false se si fa clic su .form_wrapper:

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

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

3

Allega un evento click agli elementi di livello superiore all'esterno del wrapper del modulo, ad esempio:

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

Funzionerà anche su dispositivi touch, assicurati di non includere un genitore di .form_wrapper nell'elenco dei selettori.


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

}); 

VIOLINO


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

Copiato da https://sdtuts.com/click-on-not-specified-element/

Demo live 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

l'ho fatto così:

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

Usando questo codice puoi nascondere tutti gli elementi che vuoi

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

Quello che puoi fare è associare un evento click al documento che nasconderà il menu a discesa se si fa clic su qualcosa all'esterno del menu a discesa, ma non lo nasconderà se si fa clic su qualcosa all'interno del menu a discesa, quindi il tuo evento "show" (o scorrevole o altro mostra il menu a discesa)

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

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

    });

Quindi, quando lo nascondi, separa l'evento click

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

0

Secondo i documenti , .blur()funziona per più del <input>tag. Per esempio:

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

-1, non funziona. Un'idea molto interessante, ma i documenti jQuery sono sbagliati. Vedi developer.mozilla.org/en-US/docs/Web/API/… , ad esempio: "Contrariamente a MSIE - in cui quasi tutti i tipi di elementi ricevono l'evento sfocatura - quasi tutti i tipi di elementi sui browser Gecko NON funziona con questo evento. " Inoltre, testato in Chrome, divnon è mai sfocato: gli eventi di sfocatura non possono nemmeno diffondersi dai loro figli. Infine, anche se quanto sopra non fosse vero, funzionerebbe solo se ti assicurassi che .form_wrapperfosse attivo prima che l'utente facesse clic su di esso.
Mark Amery,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.