Klicken Sie auf das äußere Menü, um in jquery zu schließen

107

Ich habe also ein Dropdown-Menü, das auf einen Klick gemäß den Geschäftsanforderungen angezeigt wird. Das Menü wird wieder ausgeblendet, nachdem Sie die Maus entfernt haben.

Aber jetzt werde ich gebeten, es an Ort und Stelle zu lassen, bis der Benutzer irgendwo auf das Dokument klickt. Wie kann dies erreicht werden?

Dies ist eine vereinfachte Version von dem, was ich jetzt habe:

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

Ich habe so etwas versucht und $('document[id!=MainOptSubMenu]').click(function()dachte, es würde alles auslösen, was nicht auf der Speisekarte stand, aber es hat nicht funktioniert.

George
quelle

Antworten:

196

Schauen Sie sich den Ansatz an, den diese Frage verwendet hat:

Wie erkenne ich einen Klick außerhalb eines Elements?

Fügen Sie dem Dokumentkörper ein Klickereignis hinzu, das das Fenster schließt. Fügen Sie dem Fenster ein separates Klickereignis hinzu, das die Weitergabe an den Dokumentkörper stoppt.
$('html').click(function() {
  //Hide the menus if visible
});

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

Jon W.
quelle
16
Es ist sehr schön, aber Sie sollten $ ('html') verwenden. click () nicht body. Der Körper hat immer die Höhe seines Inhalts. Wenn es nicht viel Inhalt gibt oder der Bildschirm sehr hoch ist, funktioniert es nur an dem Teil, den der Körper ausfüllt. Kopie von: stackoverflow.com/questions/152975/… - meo 25. Februar 11 um 15:35
NickGreen
tolle Lösung. Irgendeine Idee, warum es mit .click () und nicht mit .live funktioniert ('click', func ...?
Hat
3
Das einzige Problem bei diesem Ansatz ist, dass Objekte, die bereits einen Klick-Listener haben, der aus anderen Gründen stopPropagation hat, keine Auswirkung haben. Ich verstehe, warum es so ist, aber es ist immer noch eine Einschränkung dieser Lösung.
DanH
53

Die Antwort ist richtig, aber es wird ein Listener hinzugefügt, der jedes Mal ausgelöst wird, wenn ein Klick auf Ihre Seite auftritt. Um dies zu vermeiden, können Sie den Listener nur einmal hinzufügen:

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

Bearbeiten: Wenn Sie die stopPropagation()Schaltfläche auf der ersten Seite vermeiden möchten, können Sie diese verwenden

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');
    }
});
adriendenat
quelle
Ich sehe häufig Code wie diesen. Würde dies nicht jedes Mal, wenn auf den Menülink geklickt wird, eine neue Klickfunktion zum Dokument hinzufügen? Wenn Sie also 1000 Mal auf den Menülink klicken, ohne die Seite zu aktualisieren, haben Sie 1000 Funktionen, die Speicher beanspruchen und auch ausführen?
Eselk
Egal, ich habe die "Eins" -Funktion nicht gesehen, jetzt verstehe ich, warum dies funktioniert: api.jquery.com/one
eselk
2
schöne Lösung, aber ich musste e.stopPropagation()in Chrome verwenden, um zu verhindern, dass das erste Ereignis im one()Handler
ausgelöst wird
18

Das stopPropagation Optionen sind schlecht, da sie andere Ereignishandler stören können, einschließlich anderer Menüs, die möglicherweise enge Handler an das HTML-Element angehängt haben.

Hier ist eine einfache Lösung, die auf der Antwort von user2989143 basiert :

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

Wenn die Verwendung eines Plugins in Ihrem Fall in Ordnung ist, empfehle ich das Clickoutside-Plugin von Ben Alman, das sich hier befindet :

Die Verwendung ist so einfach:

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

hoffe das hilft.

Unterschwelliger Hash
quelle
8

2 Optionen, die Sie untersuchen können:

  • Platzieren Sie beim Anzeigen des Menüs einen großen leeren DIV dahinter, der den Rest der Seite abdeckt, und geben Sie diesem ein On-Click-Ereignis, um das Menü (und sich selbst) zu schließen. Dies ähnelt den Methoden, die bei Leuchtkästen verwendet werden, bei denen durch Klicken auf den Hintergrund der Leuchtkasten geschlossen wird
  • Fügen Sie beim Anzeigen des Menüs einen einmaligen Klickereignishandler an den Körper an, der das Menü schließt. Sie verwenden dafür '.one ()' von jQuery.
DA.
quelle
6

Ich habe eine Variante von Grsmtos Lösung gefunden und Dennis 'Lösung hat mein Problem behoben.

$(".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
        }
    });
});
cat5dev
quelle
5

Ich verwende diese Lösung mit mehreren Elementen mit demselben Verhalten auf derselben Seite:

$("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 () ist eine schlechte Idee, da dies das Standardverhalten vieler Dinge, einschließlich Schaltflächen und Links, verletzt.

user2989143
quelle
Das ist großartig, aber Sie können es vereinfachen als$target.closest('#menu-container, #menu-activator').length === 0
Code Commander
5

Ich habe vor kurzem das gleiche Problem konfrontiert. Ich habe folgenden Code geschrieben:

    $('html').click(function(e) {
      var a = e.target;
      if ($(a).parents('.menu_container').length === 0) {
        $('.ofSubLevelLinks').removeClass('active'); //hide menu item
        $('.menu_container li > img').hide(); //hide dropdown image, if any
     }
    });

Es hat bei mir perfekt funktioniert.

Namish
quelle
4

was ist damit?

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

Ich finde es nützlicher, Mousedown-Ereignis anstelle von Klick-Ereignis zu verwenden. Das Klickereignis funktioniert nicht, wenn der Benutzer mit Klickereignissen auf andere Elemente auf der Seite klickt. In Kombination mit der one () -Methode von jQuery sieht es so aus:

$("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();
});
yeeno
quelle
3

Sogar ich bin auf die gleiche Situation gestoßen und einer meiner Mentoren hat mir diese Idee vermittelt.

Schritt: 1 Wenn Sie auf die Schaltfläche klicken, auf der das Dropdown-Menü angezeigt werden soll. Fügen Sie dann den folgenden Klassennamen "more_wrap_background" zur aktuell aktiven Seite hinzu, wie unten gezeigt

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

Schritt 2 Fügen Sie dann einen Klick für das div-Tag wie hinzu

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

Dabei ist hideDropDown die Funktion, die aufgerufen werden soll, um das Dropdown-Menü auszublenden

Schritt 3 und ein wichtiger Schritt beim Ausblenden des Dropdown-Menüs ist das Entfernen der Klasse, die Sie zuvor hinzugefügt haben

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

Ich entferne, indem ich seine ID im obigen Code verwende

.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;
}
Abhimaan
quelle
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
    }
};

Und es ist besser, den Listener nur einzustellen, wenn Ihr Menü sichtbar ist, und den Listener immer zu entfernen, wenn das Menü ausgeblendet wird.

Олег Всильдеревьев
quelle
1

Ich denke, Sie brauchen so etwas: 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();               
            }
      });
  });    
});

Ich hoffe es ist nützlich für dich!

Sakata Gintoki
quelle
1

Verwenden Sie den Selektor ': sichtbar'. Wobei .menuitem die zu versteckenden Elemente sind ...

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

Oder wenn Sie bereits die .menuitem-Elemente in einer var ...

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

Es muss nicht kompliziert sein.

$(document).on('click', function() {
    $("#menu:not(:hover)").hide();
});
Jonathan Gaudé
quelle