Comment détecter un clic à l'extérieur d'un élément?

j'ai quelques menus HTML, que j'affiche complètement quand un utilisateur clique sur la tête de ces menus. Je voudrais masquer ces éléments lorsque l'utilisateur clique en dehors du menus.

est-ce possible avec jQuery?

$("#menuscontainer").clickOutsideThisElement(function() {
    // Hide the menus
});
2078
demandé sur Sergio del Amo 2008-09-30 17:17:12

30 réponses

NOTE: L'utilisation de stopEventPropagation() est quelque chose qui doit être évitée car il brise le flux d'événement normal dans le DOM. Voir cet article pour plus d'informations. Envisager d'utiliser cette méthode à la place.

attacher un événement de clic au corps du document qui ferme la fenêtre. Attachez un événement de clic séparé au conteneur qui arrête la propagation au corps du document.

$(window).click(function() {
//Hide the menus if visible
});

$('#menucontainer').click(function(event){
    event.stopPropagation();
});
1640
répondu Eran Galperin 2018-08-04 01:03:34

Vous pouvez écouter un , cliquez sur événement document , puis assurez-vous que #menucontainer n'est pas un ancêtre ou la cible de l'élément cliqué en utilisant .closest() .

si ce n'est pas le cas, alors l'élément cliqué est en dehors du #menucontainer et vous pouvez le cacher en toute sécurité.

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

Edit-2017-06-23

vous pouvez également nettoyer après l'événement auditeur si vous prévoyez de rejeter le menu et que vous voulez arrêter d'écouter pour les événements. Cette fonction nettoiera seulement l'auditeur nouvellement créé, en préservant tous les autres écouteurs de clic sur document . Avec la syntaxe 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)
}

Edit-2018-03-11

Pour ceux qui ne veulent pas utiliser jQuery. Voici le code ci-dessus dans plain 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 

NOTE: Ceci est basé sur Alex commentaire de l'utiliser juste !element.contains(event.target) au lieu de jQuery.

mais element.closest() est désormais également disponible dans tous les principaux navigateurs (la version W3C diffère légèrement de la version jQuery). Polyfills peut être trouvé ici: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest

1169
répondu Art 2018-03-11 07:15:22

Comment détecter un clic à l'extérieur d'un élément?

la raison pour laquelle cette question Est si populaire et a tant de réponses est qu'elle est trompeusement complexe. Après presque huit ans et des douzaines de réponses, je suis vraiment surpris de voir combien peu d'attention a été accordée à l'accessibilité.

je voudrais masquer ces éléments lorsque l'utilisateur clique en dehors du menus.

c'est une noble cause et c'est le numéro actuel . Le titre de la question-qui est ce que la plupart des réponses semblent tenter d'aborder-contient une malencontreuse diversion.

indice: C'est le mot "click" !

vous ne voulez pas réellement lier les gestionnaires de clic.

si vous liez, cliquez sur handlers pour fermer la boîte de dialogue, vous avez déjà échoué. La raison pour laquelle vous avez échoué est que tout le monde ne déclenche pas click événements. Les utilisateurs qui n'utilisent pas de souris seront en mesure d'échapper à votre dialogue (et votre menu pop-up est sans doute un type de dialogue) en appuyant sur Tab , et ils ne seront pas en mesure de lire le contenu derrière le dialogue sans déclencher par la suite un événement click .

alors reformulons la question.

Comment faire fermer un dialogue quand un utilisateur en a fini avec lui?

C'est le but. Malheureusement, nous devons maintenant lier l'événement userisfinishedwiththedialog , et cette liaison n'est pas si simple.

Alors, comment pouvons-nous détecter que l'utilisateur a fini d'utiliser une boîte de dialogue?

focusout événement

un bon début est de déterminer si focus a quitté la boîte de dialogue.

indice: be attention avec l'événement blur , blur ne se propage pas si l'événement était lié à la phase de bouillonnement!

jQuery focusout fera l'amende juste. Si vous ne pouvez pas utiliser jQuery, alors vous pouvez utiliser blur pendant la phase de capture:

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

aussi, pour de nombreux dialogues, vous aurez besoin de permettre au conteneur de se concentrer. Ajouter tabindex="-1" pour permettre à la boîte de dialogue de recevoir le focus dynamiquement, sans interrompre le flux de tabulations.

$('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 vous jouez avec cette démo pendant plus d'une minute, Vous devriez rapidement commencer à voir les problèmes.

la première est que le lien dans le dialogue n'est pas cliquable. Si vous tentez de cliquer dessus ou de cliquer dessus, la boîte de dialogue se ferme avant que l'interaction n'ait lieu. C'est parce que la mise au point de l'élément intérieur déclenche un événement focusout avant de déclencher à nouveau un événement focusin .

le correctif est de mettre en file d'attente le changement d'état sur la boucle d'événement. Cela peut être fait en utilisant setImmediate(...) , ou setTimeout(..., 0) pour les navigateurs qui ne prennent pas en charge setImmediate . Une fois mise en file d'attente, elle peut être annulée par un focusin suivant:

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

la seconde problème est que la fenêtre ne se ferme pas lorsque le lien est à nouveau pressé. C'est parce que la boîte de dialogue perd le focus, déclenchant le comportement de fermeture, après quoi le clic sur le lien déclenche la boîte de dialogue pour rouvrir.

comme dans le numéro précédent, l'état cible doit être géré. Étant donné que le changement d'État a déjà été mis en file d'attente, il s'agit simplement de gérer les événements de focus sur les déclencheurs de dialogue:

cela devrait sembler familier
$('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>

ces clé

si vous pensez que vous avez été fait en manipulant les états de mise au point, il ya plus que vous pouvez faire pour simplifier l'expérience de l'utilisateur.

c'est souvent une caractéristique" agréable à avoir", mais il est courant que lorsque vous avez un modal ou popup de n'importe quelle sorte que le Esc touche de fermeture.

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 vous savez que vous avez des éléments focalisables dans le dialogue, vous n'aurez pas besoin de focaliser le dialogue directement. Si vous construisez un menu, vous pouvez concentrer le premier élément du menu à la place.

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.

WAI-ARIA Roles and Autres Aides À L'Accessibilité

cette réponse couvre, espérons-le , les bases du clavier accessible et le support de la souris pour cette fonctionnalité, mais comme il est déjà assez considérable, je vais éviter toute discussion de WAI-ARIA rôles et attributs , cependant, je highly recommande que les responsables de la mise en œuvre se référer à la spécification pour les détails sur les rôles qu'ils devraient utiliser et tout autre attribut approprié.

204
répondu zzzzBov 2016-10-29 16:10:01

les autres solutions ici ne fonctionnaient pas pour moi donc j'ai dû utiliser:

if(!$(event.target).is('#foo'))
{
    // hide menu
}
129
répondu Dennis 2009-07-06 23:10:07

j'ai une application qui fonctionne de la même façon que L'exemple D'Eran, sauf que j'attache l'événement de clic au corps quand j'ouvre le menu... Un peu comme ceci:

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

  event.stopPropagation();
});

plus d'information sur jquery's one() fonction

120
répondu Joe Lencioni 2016-02-26 14:57:12
$("#menuscontainer").click(function() {
    $(this).focus();
});
$("#menuscontainer").blur(function(){
    $(this).hide();
});

me va très bien.

34
répondu user212621 2009-11-17 06:13:44

maintenant il y a un plugin pour cela: outside events ( blog post )

ce qui suit se produit lorsqu'un clickoutside handler (WLOG) est lié à un élément:

  • l'élément est ajouté à un tableau qui contient tous les éléments avec clickoutside gestionnaires
  • ( namespaces ) cliquez sur handler est lié au document (si pas déjà là)
  • sur n'importe quel cliquez sur dans le document, l'événement clickoutside "15198090920" est déclenché pour les éléments dans ce tableau qui ne sont pas égaux ou un parent du cliquez sur - cible d'événements
  • en outre, l'événement.la cible pour l'événement clickoutside est définie à l'élément sur lequel l'Utilisateur a cliqué (donc vous savez même ce que l'utilisateur a cliqué, et pas seulement qu'il a cliqué sur l'extérieur)

Donc pas les événements sont arrêtés de propagation et d'autres , cliquez sur les gestionnaires peuvent être utilisés "ci-dessus" l'élément avec l'extérieur de gestionnaire.

33
répondu Wolfram 2017-04-13 07:46:56

cela a parfaitement fonctionné pour moi!!

$('html').click(function (e) {
    if (e.target.id == 'YOUR-DIV-ID') {
        //do something
    } else {
        //do something
    }
});
28
répondu srinath 2014-03-04 14:30:47

après la recherche, j'ai trouvé trois solutions de travail (j'ai oublié les liens de page pour référence)

première solution

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

deuxième solution

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

troisième solution

<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>
28
répondu Rameez Rami 2016-10-30 16:55:18

Je ne pense pas que ce dont vous avez vraiment besoin est de fermer le menu lorsque l'utilisateur clique à l'extérieur; ce que vous avez besoin est que le menu se ferme lorsque l'utilisateur clique n'importe où sur la page. Si vous cliquez sur le menu, ou hors du menu, il devrait fermer à droite?

trouver aucune réponse satisfaisante ci-dessus m'a incité à écrire ce billet de blog l'autre jour. Pour les plus pédants, il y a un certain nombre de gotchas à noter:

  1. si vous attachez un gestionnaire d'événement de clic à l'élément de corps au moment du clic soyez sûr d'attendre le 2ème clic avant de fermer le menu, et délier l'événement. Sinon, l'événement de clic qui a ouvert le menu va bulle jusqu'à l'auditeur qui doit fermer le menu.
  2. si vous utilisez event.stopPropogation () sur un événement de clic, aucun autre élément de votre page ne peut avoir une fonctionnalité de clic-anywhere-to-close.
  3. attacher un click event handler au corps élément indéfiniment n'est pas une solution performante
  4. comparer la cible de l'événement, et ses parents au créateur du gestionnaire suppose que ce que vous voulez est de fermer le menu lorsque vous cliquez dessus, quand ce que vous voulez vraiment est de le fermer lorsque vous cliquez n'importe où sur la page.
  5. L'écoute des événements sur l'élément body rendra votre code plus fragile. Un style aussi innocent que celui-ci le briserait: body { margin-left:auto; margin-right: auto; width:960px;}
23
répondu 34m0 2011-05-19 07:00:42

comme le dit une autre affiche, il y a beaucoup de gotchas, surtout si l'élément que vous affichez (dans ce cas un menu) a des éléments interactifs. J'ai trouvé la méthode suivante assez robuste:

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

    })
});
22
répondu benb 2011-12-22 11:59:02

Vérifiez la cible d'événement de clic de fenêtre (il devrait se propager à la fenêtre, tant qu'il n'est pas capturé ailleurs), et assurez-vous que ce n'est pas l'un des éléments de menu. Si ce n'est pas le cas, alors vous êtes en dehors de votre menu.

Ou vérifier la position du clic, et voir si elle est contenue dans la zone de menu.

18
répondu Chris MacDonald 2008-09-30 13:20:30

une solution simple pour la situation est:

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

le script ci-dessus masquera le div si l'événement de clic div est déclenché.

vous pouvez voir le blog suivant pour plus d'informations: http://www.codecanal.com/detect-click-outside-div-using-javascript /

18
répondu Jitendra Damor 2017-07-10 08:32:39

Solution 1

au lieu d'utiliser event.stopPropagation() qui peut avoir des effets secondaires, il suffit de définir une simple variable flag et d'ajouter une condition if . J'ai testé ceci et j'ai bien travaillé sans aucun effet d'arrêt:

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

Solution2

avec juste un simple if condition:

$(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
    }
});
16
répondu Iman Sedighi 2016-10-30 16:51:41

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

il n'a pas de problème avec arrêt de la propagation de l'événement et supporte mieux plusieurs menus sur la même page où en cliquant sur un second menu alors qu'un premier est ouvert laissera le premier ouvert dans la solution de stopPropagation.

14
répondu Bohdan Lyzanets 2016-10-30 16:43:21

j'ai eu du succès avec quelque chose comme ça:

var $menuscontainer = ...;

$('#trigger').click(function() {
  $menuscontainer.show();

  $('body').click(function(event) {
    var $target = $(event.target);

    if ($target.parents('#menuscontainer').length == 0) {
      $menuscontainer.hide();
    }
  });
});

la logique est la suivante: lorsque #menuscontainer est affiché, liez un gestionnaire de clic au corps qui cache #menuscontainer seulement si la cible (du clic) n'en est pas un enfant.

13
répondu Chu Yeow 2018-08-03 07:42:56

j'ai trouvé cette méthode dans un plugin jQuery calendar.

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);
12
répondu nazar kuliyev 2016-10-30 16:15:45

si vous êtes un script pour IE et FF 3.* et vous voulez juste savoir si le clic s'est produit dans une certaine zone de boîte, vous pouvez également utiliser quelque chose comme:

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;}
8
répondu Erik 2009-08-14 14:08:21

au lieu d'utiliser l'interruption du flux, l'événement flou/focus ou toute autre technique délicate, il suffit de faire correspondre le flux d'événement avec la parenté de l'élément:

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

pour supprimer cliquez sur outside event listener, simplement:

$(document).off("click.menu-outside");
8
répondu mems 2013-06-05 15:05:20

Voici la solution JavaScript vanille pour les futurs téléspectateurs.

en cliquant sur un élément dans le document, si l'id de l'élément cliqué est basculé, ou si l'élément caché n'est pas caché et que l'élément caché ne contient pas l'élément cliqué, basculer l'élément.

(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 vous allez avoir plusieurs bascule sur la même page, vous pouvez utiliser quelque chose comme ceci:

  1. ajouter le nom de classe hidden à l'article pliable.
  2. après le clic de document, fermer tous les éléments cachés qui ne contiennent pas l'élément cliqué et ne sont pas cachés
  3. Si l'élément cliqué est une bascule, bascule l'élément spécifié.

(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>
8
répondu Tiny Giant 2016-10-30 16:52:55

L'événement a une propriété appelée événement.chemin de l'élément qui est une "liste statique ordonnée de tous ses ancêtres dans l'ordre des arbres" . Pour vérifier si un événement provient d'un élément DOM spécifique ou d'un de ses enfants, il suffit de vérifier le chemin pour cet élément DOM spécifique. Il peut également être utilisé pour vérifier plusieurs éléments par logiquement OR dans le contrôle de l'élément dans la fonction some .

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

donc pour votre cas il devrait être

$("body").click(function() {
  target = $("#menuscontainer")[0];
  flag = event.path.some(function(el, i, arr) {
    return (el == target)
  });
  if (!flag) {
    // Hide the menus
  }
});
7
répondu Dan Philip 2017-05-01 15:03:59

Crochet un écouteur d'événement clic sur le document. À l'intérieur de l'écouteur d'événements, vous pouvez regarder "event object , en particulier, l'événement .cible pour voir quel élément a été cliqué:

$(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");
    }
});
6
répondu Salman A 2012-05-03 09:21:57

utiliser:

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();
});
6
répondu webenformasyon 2017-02-22 13:00:15
$(document).click(function() {
    $(".overlay-window").hide();
});
$(".overlay-window").click(function() {
    return false;
});

, Si vous cliquez sur le document, de masquer un élément donné, sauf si vous cliquez sur le même élément.

5
répondu Rowan 2011-09-20 18:44:18

Upvote pour la réponse la plus populaire, mais ajouter

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

donc, un clic sur une barre de défilement ne cache pas votre élément cible.

5
répondu bbe 2015-07-25 21:33:38

pour une utilisation plus facile, et un code plus expressif, j'ai créé un plugin jQuery pour ceci:

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

Note: cible est l'élément que l'utilisateur a cliqué. Mais le callback est toujours exécuté dans le contexte de l'élément original, donc vous pouvez utiliser ce comme vous vous y attendiez dans un callback jQuery.

Plugin:

$.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;
};

par défaut, l'écouteur de clics event est placé sur le document. Cependant, si vous voulez limiter la portée de l'écouteur d'événements, vous pouvez passer dans un objet jQuery représentant un élément de niveau parent qui sera le parent supérieur auquel les clics seront écoutés. Cela évite les écouteurs d'événements inutiles au niveau du document. Évidemment, cela ne fonctionnera pas à moins que l'élément parent fourni soit un parent de votre Élément initial.

utiliser comme suit:

$('div.my-element').clickOut($('div.my-parent'), function(target) { 
    //do something here...
});
5
répondu Matt Goodwin 2016-05-15 21:27:58

C'est ma solution à ce problème:

$(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();
  });
});
4
répondu Spencer Fry 2012-03-21 16:24:38

j'ai fini par faire quelque chose comme ça:

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

j'ai un bouton de fermeture dans le nouveau conteneur pour les besoins de L'interface utilisateur conviviale. J'ai dû utiliser return false pour ne pas passer. Bien sûr, avoir un A HREF là-bas pour vous emmener quelque part serait sympa, ou vous pourriez appeler quelques trucs ajax à la place. De toute façon, cela fonctionne bien pour moi. Ce que je voulais.

4
répondu Webmaster G 2013-11-19 01:40:52

nous avons mis en place une solution, basée en partie sur un commentaire d'un utilisateur ci-dessus, qui fonctionne parfaitement pour nous. Nous l'utilisons pour masquer une zone de recherche / résultats lorsque vous cliquez en dehors de ces éléments, à l'exclusion de l'élément à l'origine.

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

il vérifie si la boîte de recherche est déjà visible en premier, et dans notre cas, il supprime également une classe active sur le bouton de recherche hide/show.

4
répondu Scott Richardson 2015-07-08 01:05:46

fonction:

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

Utilisation:

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

et les fonctions sont très simples:

ShowTree: function(event) {
    this.data_span.show();
}
Hide: function() {
    this.data_span.hide();
}
4
répondu Neco 2016-10-30 16:07:48