2010-05-19 5 views
99

J'ai donc un menu déroulant qui s'affiche sur un clic, selon les exigences de l'entreprise. Le menu devient caché à nouveau après que vous la souris.Cliquez hors menu pour fermer dans jquery

Maintenant, on me demande de le faire rester en place jusqu'à ce que l'utilisateur clique n'importe où sur le document. Comment cela peut-il être accompli?

Ceci est une version simplifiée de ce que j'ai maintenant:

$(document).ready(function() { 
    $("ul.opMenu li").click(function(){ 
    $('#MainOptSubMenu',this).css('visibility', 'visible'); 
    }); 

    $("ul.opMenu li").mouseleave(function(){ 
     $('#MainOptSubMenu',this).css('visibility', 'hidden'); 
    }); 
}); 



<ul class="opMenu"> 
    <li id="footwo" class=""> 
    <span id="optImg" style="display: inline-block;"> <img src="http://localhost.vmsinfo.com:8002/insight/images/options-hover2.gif"/> </span> 
     <ul id="MainOptSubMenu" style="visibility: hidden; top: 25px; border-top: 0px solid rgb(217, 228, 250); background-color: rgb(217, 228, 250); padding-bottom: 15px;"> 
     <li>some</li> 
     <li>nav</li> 
     <li>links</li> 
     </ul> 
    </li> 
</ul> 

J'ai essayé quelque chose comme ça $('document[id!=MainOptSubMenu]').click(function() pensant qu'il déclencherait sur tout ce qui était pas le menu, mais cela n'a pas fonctionné.

+0

J'ai une réponse ici. > [http: // stackoverflow.com/questions/152975/how-do-je-détecter-un-clic-dehors-un-élément/43405204 # 43405204] (http://stackoverflow.com/questions/152975/how-do-i-detect-a -click-outside-an-element/43405204 # 43405204) –

+0

Copie possible de [Comment puis-je détecter un clic en dehors d'un élément?] (http://stackoverflow.com/questions/152975/how-do-i-detect- a-click-outside-an-element) –

Répondre

182

Jetez un oeil à l'approche cette question utilisée:

How do I detect a click outside an element?

Joindre un événement click sur le corps du document qui ferme la fenêtre. Attachez un événement click distinct à la fenêtre qui arrête la propagation dans le corps du document.
$('html').click(function() { 
    //Hide the menus if visible 
}); 

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

+13

c'est très beau mais vous devez utiliser $ ('html'). click() pas de corps. Le corps a toujours la hauteur de son contenu. Il n'y a pas beaucoup de contenu ou l'écran est très haut, ça ne marche que sur la partie remplie par le corps. Copier de: http://stackoverflow.com/questions/152975/how-to-detect-a-click-outside-an-element - meo 25 fév. 11 à 15:35 – NickGreen

+0

grande solution. Quelle est la raison pour laquelle cela fonctionne avec .click() et non avec .live ('click', func ...? – Hat

+3

Le seul problème avec cette approche est que les objets qui ont déjà un écouteur clickpropagation pour d'autres raisons n'ont aucun effet. Je comprends pourquoi c'est le cas, mais c'est toujours une limitation de cette solution – DanH

7

2 options que vous pouvez étudier:

  • En montrant du menu, placez un grand vide DIV derrière elle couvre le reste de la page et donnent qu'une sur -clic événement pour fermer le menu (et lui-même). Cela s'apparente aux méthodes utilisées avec les visionneuses où cliquer sur l'arrière-plan ferme la visionneuse
  • Lors de l'affichage du menu, attachez un gestionnaire d'événement de clic unique sur le corps qui ferme le menu. Vous utilisez '.one()' de jQuery pour cela.
+0

Merci, je travaille sur un site Wordpress et la première solution a fonctionné pour moi! –

16

Si vous utilisez un plug-in est ok en vous cas, alors je suggère que le plugin clickoutside Ben Alman situé here:

son utilisation est aussi simple que cela:

$('#menu').bind('clickoutside', function (event) { 
    $(this).hide(); 
}); 

espérons que cette aide.

+1

Ce plugin est très léger et utile, facile à implémenter aussi Merci de partager le lien –

+0

super plugin, n'a pas été mis à jour depuis un certain temps mais fonctionne toujours très bien – uberweb

1

Je pense que vous avez besoin quelque chose comme ceci: http://jsfiddle.net/BeenYoung/BXaqW/3/

$(document).ready(function() { 
    $("ul.opMenu li").each(function(){ 
     $(this).click(function(){ 
      if($(this).hasClass('opened')==false){   
       $('.opMenu').find('.opened').removeClass('opened').find('ul').slideUp(); 
       $(this).addClass('opened'); 
       $(this).find("ul").slideDown(); 
      }else{ 
       $(this).removeClass('opened'); 
       $(this).find("ul").slideUp();    
      } 
     }); 
    });  
}); 

J'espère utile pour vous!

48

La réponse est correcte, mais il va ajouter un écouteur qui sera déclenché chaque fois qu'un clic se produit sur votre page. Pour éviter cela, vous pouvez ajouter l'écouteur pour une seule fois:

$('a#menu-link').on('click', function(e) { 
    e.preventDefault(); 
    e.stopPropagation(); 

    $('#menu').toggleClass('open'); 

    $(document).one('click', function closeMenu (e){ 
     if($('#menu').has(e.target).length === 0){ 
      $('#menu').removeClass('open'); 
     } else { 
      $(document).one('click', closeMenu); 
     } 
    }); 
}); 

Edit: si vous voulez éviter la stopPropagation() sur le bouton initial, vous pouvez utiliser cette

var $menu = $('#menu'); 

$('a#menu-link').on('click', function(e) { 
    e.preventDefault(); 

    if (!$menu.hasClass('active')) { 
     $menu.addClass('active'); 

     $(document).one('click', function closeTooltip(e) { 
      if ($menu.has(e.target).length === 0 && $('a#menu-link').has(e.target).length === 0) { 
       $menu.removeClass('active'); 
      } else if ($menu.hasClass('active')) { 
       $(document).one('click', closeTooltip); 
      } 
     }); 
    } else { 
     $menu.removeClass('active'); 
    } 
}); 
+0

Je vois beaucoup de code comme ça, cela n'ajouterait pas une nouvelle fonction de clic au document chaque fois que le lien du menu Si vous cliquez sur le lien du menu 1000 fois sans actualiser la page, vous aurez 1000 fonctions prenant de la mémoire et également en cours d'exécution? – eselk

+0

Nevermind, je n'ai pas vu la fonction "un", maintenant je comprends pourquoi cela fonctionne: http://api.jquery.com/one/ – eselk

+2

bonne solution mais j'ai dû utiliser 'e.stopPropagation()' dans Chrome pour empêcher le premier événement de tirer dans le 'one()' gestionnaire – antfx

4

Qu'en est-ce?

$(this).mouseleave(function(){ 
     var thisUI = $(this); 
     $('html').click(function(){ 
       thisUI.hide(); 
      $('html').unbind('click'); 
     }); 
    }); 
2

Même si je suis tombé sur la même situation et que l'un de mes mentors m'a fait part de cette idée.

étape: 1 lorsque vous cliquez sur le bouton sur lequel nous devrions afficher le menu déroulant. puis ajouter le nom de classe ci-dessous « more_wrap_background » à la page active en cours comme indiqué ci-dessous

$('.ui-page-active').append("<div class='more_wrap_background' id='more-wrap-bg'> </div>"); 

étape 2 puis ajoutez clique pour la balise div comme

$(document).on('click', '#more-wrap-bg', hideDropDown); 

où hideDropDown est la fonction être appelé pour masquer le menu déroulant

Étape-3 et étape importante tout en cachant le menu déroulant est que supprimer cette classe que vous avez ajouté précédemment comme

$('#more-wrap-bg').remove(); 

je retire en utilisant son identifiant dans le code ci-dessus

.more_wrap_background { 
    top: 0; 
    padding: 0; 
    margin: 0; 
    background: rgba(0, 0, 0, 0.1); 
    position: fixed; 
    display: block; 
    width: 100% !important; 
    z-index: 999;//should be one less than the drop down menu's z-index 
    height: 100% !important; 
} 
3

J'ai trouvé une variante de Grsmto's solution et Dennis' solution fixe mon problème.

$(".MainNavContainer").click(function (event) { 
    //event.preventDefault(); // Might cause problems depending on implementation 
    event.stopPropagation(); 

    $(document).one('click', function (e) { 
     if(!$(e.target).is('.MainNavContainer')) { 
      // code to hide menus 
     } 
    }); 
}); 
2
$("html").click(onOutsideClick); 
onOutsideClick = function(e) 
{ 
    var t = $(e.target); 
    if (!(
     t.is("#mymenu") ||  //Where #mymenu - is a div container of your menu 
     t.parents("#mymenu").length > 0 
     ) ) 
    { 
     //TODO: hide your menu 
    } 
}; 

Et mieux définir l'auditeur que lorsque votre menu est visible et retirez toujours l'auditeur après le menu devient caché.

3

Je trouve plus utile d'utiliser mousedown-event au lieu de click-event. L'événement click ne fonctionne pas si l'utilisateur clique sur d'autres éléments de la page avec des événements click. En combinaison avec la méthode de l'un() jQuery il ressemble à ceci:

$("ul.opMenu li").click(function(event){ 

    //event.stopPropagation(); not required any more 
    $('#MainOptSubMenu').show(); 

    // add one mousedown event to html 
    $('html').one('mousedown', function(){ 
     $('#MainOptSubMenu').hide(); 
    }); 
}); 

// mousedown must not be triggered inside menu 
$("ul.opMenu li").bind('mousedown', function(evt){ 
    evt.stopPropagation(); 
}); 
4

J'utilise cette solution avec plusieurs éléments avec le même comportement dans la même page:

$("html").click(function(event){ 
    var otarget = $(event.target); 
    if (!otarget.parents('#id_of element').length && otarget.attr('id')!="id_of element" && !otarget.parents('#id_of_activator').length) { 
     $('#id_of element').hide(); 
    } 
}); 

stopPropagation() est une mauvaise idée , cela brise le comportement standard de beaucoup de choses, y compris les boutons et les liens.

+0

C'est génial, mais vous pouvez le simplifier comme '$ target.closest ('# menu-container, # menu-activator'). longueur === 0' –

12

Les options stopPropagation sont incorrectes car elles peuvent interférer avec d'autres gestionnaires d'événements, y compris d'autres menus qui peuvent contenir des gestionnaires proches de l'élément html.

Voici une solution simple basée sur la réponse de user2989143:

$("html").click(function(event) { 
    if ($(event.target).closest('#menu-container, #menu-activator').length === 0) { 
     $('#menu-container').hide(); 
    } 
}); 
1

Utilisez le ': visible' sélecteur. Où .menuitem est le var ... dans un

var menitems = $('.menuitem'); 
$('body').click(function(){ 
    menuitems.filter(':visible').hide('fast'); 
}); 
4

à cacher élément (s) ...

$('body').click(function(){ 
    $('.menuitem:visible').hide('fast'); 
}); 

Ou si vous avez déjà l'élément .menuitem (s) Je récemment fait face au même problème. J'ai écrit le code suivant:

Cela a fonctionné pour moi parfaitement.