Utilisez jQuery pour masquer un DIV lorsque l'utilisateur clique en dehors de celui-ci

968

J'utilise ce code:

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

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

Et ce HTML :

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

Le problème est que j'ai des liens à l'intérieur du divet quand ils ne fonctionnent plus lorsqu'ils sont cliqués.

Scott Yu - construit des trucs
la source
6
En utilisant du javascript simple, vous pouvez essayer quelque chose comme ceci: jsfiddle.net/aamir/y7mEY
Aamir Afridi
en utilisant $('html')ou $(document)serait mieux que$('body')
Adrien Be

Réponses:

2485

Eu le même problème, est venu avec cette solution facile. Cela fonctionne même récursivement:

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

la source
19
Mettez-le simplement dans mon projet, mais avec un ajustement mineur, en utilisant un tableau d'éléments pour les parcourir tous en même temps. jsfiddle.net/LCB5W
Thomas
5
@mpelzsherman De nombreuses personnes ont indiqué que l'extrait de code fonctionne sur les appareils tactiles, mais depuis la publication du message, ces commentaires ont quelque peu disparu. TBH Je ne sais pas si j'ai utilisé "mouseup" pour une raison spécifique mais si cela fonctionne aussi avec "click", je ne vois aucune raison pour laquelle vous ne devriez pas utiliser "click".
6
J'avais besoin que le conteneur soit caché une fois avec cet événement, ce rappel devrait être détruit lorsqu'il est utilisé. Pour ce faire, j'ai utilisé un espace de noms sur l'événement click avec bind ("click.namespace") et lorsque l'événement s'est produit, j'appelle unbind ("click.namespace"). Et enfin, j'ai utilisé $ (e.target) .closest (". Container"). Length pour reconnaître le conteneur ... Donc, je n'ai utilisé aucune astuce de cette réponse: D
Loenix
80
N'oubliez pas d'utiliser $("YOUR CONTAINER SELECTOR").unbind( 'click', clickDocument );juste à côté .hide(). Alors documentne continuez pas à écouter les clics.
brasofilo
12
Pour les meilleures pratiques, j'avais écrit $(document).on("mouseup.hideDocClick", function () { ... });dans la fonction qui ouvre le conteneur et $(document).off('.hideDocClick');sur la fonction de masquage. En utilisant des espaces de noms, je ne supprime pas les autres mouseupécouteurs possibles attachés au document.
campsjos
204

Vous feriez mieux d'aller avec quelque chose comme ça:

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
la source
Que c'est intelligent! Cette technique est-elle standard?
advait
@advait je ne l'ai pas vu utilisé auparavant. Tout tourne autour du hovergestionnaire d'événements, ce qui ouvre de nombreuses possibilités.
Makram Saleh
5
Je ne considère pas cela comme une bonne solution car cela laisse les gens penser qu'il est correct de remplir l'objet window (= en utilisant des variables globales).
1
Juste pour ajouter quelque chose à ce que @ prc322 a dit, vous pouvez encapsuler votre code avec une fonction anonyme et le faire appeler immédiatement. (function() { // ... code })(); Je ne me souviens pas du nom de ce modèle, mais c'est super utile! Toutes vos variables déclarées résideront à l'intérieur de la fonction et ne pollueront pas l'espace de noms global.
pedromanoel
3
@ prc322 Si vous ne savez même pas comment changer la portée d'une variable, alors vous avez raison, cette solution n'est pas bonne pour vous ... et JavaScript non plus. Si vous copiez et collez simplement du code à partir de Stack Overflow, vous allez avoir beaucoup plus de problèmes que d'écraser éventuellement quelque chose dans l'objet fenêtre.
Gavin
87

Ce code détecte tout événement de clic sur la page, puis masque l' #CONTAINERélément si et seulement si l'élément cliqué n'était ni l' #CONTAINERélément ni l'un de ses descendants.

$(document).on('click', function (e) {
    if ($(e.target).closest("#CONTAINER").length === 0) {
        $("#CONTAINER").hide();
    }
});
Cas
la source
C'est parfait!!
Mohd Abdul Mujib
@ 9KSoft Je suis content qu'il ait pu vous aider. Merci pour vos commentaires et bonne chance.
Affaire
Cette solution a parfaitement fonctionné pour moi en utilisant un div comme conteneur!
JCO9
76

Vous souhaiterez peut-être vérifier la cible de l'événement de clic qui se déclenche pour le corps au lieu de compter sur stopPropagation.

Quelque chose comme:

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

De plus, l'élément body peut ne pas inclure tout l'espace visuel affiché dans le navigateur. Si vous remarquez que vos clics ne sont pas enregistrés, vous devrez peut-être ajouter à la place le gestionnaire de clics pour l'élément HTML.

David Andres
la source
Oui, maintenant les liens fonctionnent! Mais pour une raison quelconque, lorsque je clique sur le lien, il le déclenche deux fois.
Scott Yu - construit des trucs le
J'ai fini par utiliser une variante de cela. Je vérifie d'abord si l'élément est visible puis si le target.hasClass je le cache.
Hawkee
et n'oubliez pas e.stopPropagation();si vous avez un autre auditeur de clics
Darin Kolev
2
-1. Cela masque le form_wrapperlorsque vous cliquez sur l'un de ses enfants, ce qui n'est pas le comportement souhaité. Utilisez plutôt la réponse de prc322.
Mark Amery
38

DÉMO en direct

Vérifier que la zone de clic n'est pas dans l'élément ciblé ou dans son enfant

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

MISE À JOUR:

jQuery stop propagation est la meilleure solution

DÉMO en direct

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

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

$(document).click(function(){
    $(".dropdown").hide();
});
MaxEcho
la source
Merci pour la mise à jour, parfait! Cela fonctionne-t-il sur les appareils tactiles?
FFish
1
Dans le cas, vous avez plusieurs listes déroulantes sur une page. Je pense que vous devrez fermer toutes les listes déroulantes avant d'ouvrir celle- clickedci. Sinon, stopPropagationcela rendrait possible l'ouverture simultanée de plusieurs listes déroulantes.
T04435
19
$(document).click(function(event) {
    if ( !$(event.target).hasClass('form_wrapper')) {
         $(".form_wrapper").hide();
    }
});
meder omuraliev
la source
2
Hmmm ... Si je clique sur quelque chose À L'INTÉRIEUR du div, le div entier disparaît pour une raison quelconque.
Scott Yu - construit des trucs le
11
Au lieu de vérifier si la cible a la classe, essayez: if ($ (event.target) .closest ('. Form_wrapper) .get (0) == null) {$ (". Form_wrapper"). Hide (); } Cela garantira que cliquer sur des éléments à l'intérieur du div ne masquera pas le div.
John Haager
17

Mise à jour de la solution pour:

  • utilisez plutôt mouseenter et mouseleave
  • de survoler utiliser la liaison d'événements en direct

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
la source
1
.liveest désormais obsolète ; utiliser à la .onplace.
Brett
15

Une solution sans jQuery pour la réponse la plus populaire :

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
la source
bindça ne marche pas. Pourriez-vous corriger la fonction pour la faire fonctionner?
Memmo
9

Démo en direct avec ESCfonctionnalité

Fonctionne à la fois sur ordinateur et sur mobile

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

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

Si dans certains cas, vous devez être sûr que votre élément est vraiment visible lorsque vous cliquez sur le document: if($pop.is(':visible') && (notH||e.which==27)) $pop.hide();

Roko C. Buljan
la source
8

Est-ce que quelque chose comme ça ne marcherait pas?

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

});

ou

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

});
MRVDOG
la source
4
Cette réponse n'est pas correcte. Comme beaucoup de réponses ici, cela masquera le .form_wrapperlorsque vous cliquez sur ses enfants (entre autres problèmes).
Mark Amery
6

Encore plus léger:

$("html").click(function(){ 
    $(".wrapper:visible").hide();
});
Olivenbaum
la source
4
Cette réponse n'est pas correcte. Cela masquera le .wrappern'importe où vous cliquez sur la page, ce qui n'est pas ce qui a été demandé.
Mark Amery
6

Au lieu d'écouter chaque clic sur le DOM pour masquer un élément spécifique, vous pouvez définir tabindexle parent <div>et écouter les focusoutévénements.

Le réglage tabindexs'assurera que l' blurévénement est déclenché sur le <div>(normalement il ne le ferait pas).

Ainsi, votre HTML ressemblerait à:

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

Et votre JS:

$('.form_wrapper').on('focusout', function(event){
    $('.form_wrapper').hide();
});
oscar
la source
5

Et pour les appareils tactiles comme IPAD et IPHONE, nous pouvons utiliser le code suivant

$(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
la source
5

Voici un jsfiddle que j'ai trouvé sur un autre fil, fonctionne également avec la touche 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
la source
Je vois qu'il détecte si l'événement «click» se trouve dans l'élément #test .. a essayé les liens comme jsfiddle.net/TA96A et semble fonctionner.
Thomas W
Oui, il semble que jsfiddle bloque les liens externes. Si vous utilisez http: // jsfiddle.net, vous verrez que la page de résultats traite le lien :)
djv
5

Construit à partir de la réponse impressionnante 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);
    }
  });
}

Cela ajoute quelques éléments ...

  1. Placé dans une fonction avec un rappel avec des arguments "illimités"
  2. Ajout d'un appel à .off () de jquery associé à un espace de noms d'événement pour dissocier l'événement du document une fois qu'il a été exécuté.
  3. Touchend inclus pour la fonctionnalité mobile

J'espère que ça aidera quelqu'un!

WiseOlMan
la source
4

si vous avez des problèmes avec ios, mouseup ne fonctionne pas sur l'appareil Apple.

est-ce que mousedown / mouseup dans jquery fonctionne pour l'ipad?

j'utilise ceci:

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

          if (container.has(e.target).length === 0)
          {
              container.hide();
          }
      });
user2271066
la source
4

(Ajout juste à la réponse de prc322.)

Dans mon cas, j'utilise ce code pour masquer un menu de navigation qui apparaît lorsque l'utilisateur clique sur un onglet approprié. J'ai trouvé utile d'ajouter une condition supplémentaire, à savoir que la cible du clic en dehors du conteneur n'est pas un lien.

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

En effet, certains des liens de mon site ajoutent du nouveau contenu à la page. Si ce nouveau contenu est ajouté en même temps que le menu de navigation disparaît, il peut être désorientant pour l'utilisateur.

shngrdnr
la source
4

Tant de réponses, doit être un droit de passage pour en avoir ajouté une ... Je n'ai pas vu de réponses actuelles (jQuery 3.1.1) - donc:

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

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

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

pest le nom de l'élément. Où l'on peut également passer l'id ou le nom de classe ou d'élément.

Abhishek
la source
3

Renvoyez false si vous cliquez sur .form_wrapper:

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

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

Attachez un événement de clic aux éléments de niveau supérieur en dehors de l'encapsuleur de formulaire, par exemple:

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

Cela fonctionnera également sur les appareils tactiles, assurez-vous simplement de ne pas inclure un parent de .form_wrapper dans votre liste de sélecteurs.

ThornberryPie
la source
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");  

}); 

VIOLON

SharmaPattar
la source
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
la source
3

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

Démo en direct 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
la source
2

je l'ai fait comme ça:

var close = true;

$(function () {

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

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


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

});
user2822517
la source
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
la source
2

En utilisant ce code, vous pouvez masquer autant d'éléments que vous le souhaitez

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
la source
1

Ce que vous pouvez faire est de lier un événement de clic au document qui masquera la liste déroulante si quelque chose en dehors de la liste déroulante est cliqué, mais ne le masquera pas si quelque chose à l'intérieur de la liste déroulante est cliqué, donc votre événement "show" (ou glissé ou autre) montre la liste déroulante)

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

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

    });

Ensuite, lorsque vous le cachez, dissociez l'événement de clic

$(document).unbind('click');
jeffsaracco
la source
0

Selon les documents , .blur()fonctionne plus que la <input>balise. Par exemple:

$('.form_wrapper').blur(function(){
   $(this).hide();
});
Bizley
la source
-1, ne fonctionne pas. Idée très intéressante, mais les documents jQuery sont erronés. Voir developer.mozilla.org/en-US/docs/Web/API/… , par exemple: "Contrairement à MSIE - dans lequel presque toutes sortes d'éléments reçoivent l'événement flou - presque toutes sortes d'éléments sur les navigateurs Gecko ne fonctionne PAS avec cet événement. " En outre, testé dans Chrome, et divs jamais flou - les événements de flou ne peuvent même pas leur venir de leurs enfants. Enfin, même si ce qui précède n'était pas vrai, cela ne fonctionnerait que si vous vous assuriez que le .form_wrapperétait au point avant que l'utilisateur ne clique dessus.
Mark Amery