Unikaj rozwijanego menu zamykającego kliknięcie wewnątrz


310

Mam menu rozwijane Bootstrap na Twitterze. Jak wszyscy użytkownicy Twitter Bootstrap wiedzą, menu rozwijane zamyka się po kliknięciu (nawet kliknięciu w nim).

Aby tego uniknąć, mogę łatwo dołączyć moduł obsługi zdarzeń kliknięcia do menu rozwijanego i po prostu dodać słynny event.stopPropagation().

<ul class="nav navbar-nav">
  <li class="dropdown mega-dropdown">
    <a href="javascript:;" class="dropdown-toggle" data-toggle="dropdown">
      <i class="fa fa-list-alt"></i> Menu item 1
      <span class="fa fa-chevron-down pull-right"></span>
    </a>
    <ul class="dropdown-menu mega-dropdown-menu">
      <li>
        <div id="carousel" class="carousel slide" data-ride="carousel">
          <ol class="carousel-indicators">
            <li data-slide-to="0" data-target="#carousel"></li>
            <li class="active" data-slide-to="1" data-target="#carousel"></li>
          </ol>
          <div class="carousel-inner">
            <div class="item">
              <img alt="" class="img-rounded" src="img1.jpg">
            </div>
            <div class="item active">
              <img alt="" class="img-rounded" src="img2.jpg">
            </div>
          </div>
          <a data-slide="prev" role="button" href="#carousel" 
             class="left carousel-control">
            <span class="glyphicon glyphicon-chevron-left"></span>
          </a>
          <a data-slide="next" role="button" href="#carousel" 
             class="right carousel-control">
            <span class="glyphicon glyphicon-chevron-right"></span>
          </a>
        </div>
      </li>
    </ul>
  </li>
</ul>

Wygląda to jednak na łatwe i bardzo powszechne zachowanie, a ponieważ carousel-controls(jak również carousel indicators) procedury obsługi zdarzeń są delegowane do documentobiektu, clickzdarzenie na tych elementach ( kontrolki poprzednia / następna , ...) zostanie „zignorowane”.

$('ul.dropdown-menu.mega-dropdown-menu').on('click', function(event){
    // The event won't be propagated up to the document NODE and 
    // therefore delegated events won't be fired
    event.stopPropagation();
});

Opieranie się na rozwijanym menu hide/ hiddenzdarzeniach Bootstrap nie jest rozwiązaniem z następujących powodów:

  • Podany obiekt zdarzenia dla obu procedur obsługi zdarzeń nie zawiera odniesienia do klikniętego elementu
  • Nie mam kontroli nad zawartością menu rozwijanego, więc dodanie flagklasy lub atrybutu nie jest możliwe

To skrzypce jest normalne zachowanie i to skrzypce jest z event.stopPropagation()dodaną.

Aktualizacja

Dzięki Romanowi za odpowiedź . Znalazłem również odpowiedź, którą możesz znaleźć poniżej .


1. Twój jsfiddle nie działa. 2. Co dokładnie chcesz osiągnąć?
paulalexandru

1
@paulalexandru, zaktualizowano, dodano dwa skrzypce. Jedno domyślne zachowanie i jedno z modyfikacją. Spróbuj kliknąć następny i poprzedni przycisk lub wskaźniki. W pierwszym przykładzie menu ukrywa się i slajdy karuzeli. lub drugi przykład: menu pozostaje otwarte, ale karuzela nie przesuwa się od event propagationmomentu zatrzymania.
php-dev

@paulalexandru Rozumiem, prawda?
php-dev

@ php-dev: zaktualizowałem go ponownie ze względu na wyzwanie, teraz jest idealny ... zobacz wersję demo.
Luca Filosofi,

Odpowiedzi:


373

Usunięcie atrybutu danych data-toggle="dropdown"i wdrożenie otwarcia / zamknięcia menu rozwijanego może być rozwiązaniem.

Po pierwsze, kliknij łącze, aby otworzyć / zamknąć menu w następujący sposób:

$('li.dropdown.mega-dropdown a').on('click', function (event) {
    $(this).parent().toggleClass('open');
});

a następnie słuchanie kliknięć poza menu rozwijanym, aby je zamknąć w następujący sposób:

$('body').on('click', function (e) {
    if (!$('li.dropdown.mega-dropdown').is(e.target) 
        && $('li.dropdown.mega-dropdown').has(e.target).length === 0 
        && $('.open').has(e.target).length === 0
    ) {
        $('li.dropdown.mega-dropdown').removeClass('open');
    }
});

Oto demo: http://jsfiddle.net/RomaLefrancois/hh81rhcm/2/


2
To rozwiązanie działa dobrze. Nagroda powinna zostać przyznana, jeśli nie ma innej odpowiedzi.
php-dev

1
Twoje rozwiązanie działa, jest ogólne i „popularne”. Nagroda powinna zostać przyznana za twoją odpowiedź. Znalazłem też odpowiedź, spójrz na nią poniżej;)
php-dev

1
@Cichy ... wystarczy zmodyfikować pierwszy moduł obsługi w ten sposób ... $ ('li.dropdown.mega-dropdown a'). On ('click', function (event) {$ ('li.dropdown.mega-dropdown .open '). removeClass (' open '); $ (this) .parent (). toggleClass (' open ');});
dsaket

63
Ta preferowana odpowiedź to hack. łał!!! Oto prostsza odpowiedź BOOTSTRAP 4 ALPHA, aby zapobiec kliknięciu w środku w mega rozwijanym menu. // PREVENT INSIDE CLICK DROPDOWN $('.dropdown-menu').on("click.bs.dropdown", function (e) { e.stopPropagation(); e.preventDefault(); });
Frank Thoeny

7
e.stopPropagation()jest najlepszym rozwiązaniem.
nacholibre

332

To również powinno pomóc

$(document).on('click', 'someyourContainer .dropdown-menu', function (e) {
  e.stopPropagation();
});

33
Myślę, że to z pewnością najprostsze rozwiązanie tego problemu. Kciuki w górę - właśnie przetestowałem ten i działa!
Torsten Barthel

13
To zdecydowanie najlepsze rozwiązanie.
cichy

3
To najczęstsze rozwiązanie, ale mam inne wymagania. Przeczytaj uważnie moje pytanie :)
php-dev

4
Najlepsze rozwiązanie dla utrzymania otwartego menu po kliknięciu.
Matt Pierce

2
Rzeczywiście najlepsze rozwiązanie. Użyłem osobiście, '.dropdown-menu :not(.dropdown-item)'więc kliknięcie przycisku „a” dropdown-itempowoduje zamknięcie wyskakującego okienka, a kliknięcie przycisku „ dropdown-headernie”.
Benjamin

41

Bootstrap zapewnia następującą funkcję:

                 | To zdarzenie jest uruchamiane natychmiast po metodzie instancji ukrywania
hide.bs.dropdown | został nazwany. Przełączający element kotwiczący jest dostępny jako
                 | relatedTarget właściwość zdarzenia.

Dlatego wdrożenie tej funkcji powinno umożliwić wyłączenie rozwijania z zamykania.

$('#myDropdown').on('hide.bs.dropdown', function (e) {
    var target = $(e.target);
    if(target.hasClass("keepopen") || target.parents(".keepopen").length){
        return false; // returning false should stop the dropdown from hiding.
    }else{
        return true;
    }
});

2
@Vartan, także zdarzenie targetwłaściwość jest li.dropdownThe relatedTargetjest a.dropdown-toggle. W związku z tym nie można odwoływać się do klikniętego elementu w hidemodule obsługi zdarzeń.
php-dev

2
hasClass pobiera nazwę klasy, a nie selektor CSS. target.hasClass(".keepopen")powinno być target.hasClass("keepopen"). W przeciwnym razie kod nie będzie działał.
Hugh Guiney,

3
Przeskanowałem Internet i jest to jak dotąd najbardziej inteligentne rozwiązanie, z tego powodu ... wiele innych metod wymaga podejścia polegającego na zatrzymaniu zdarzenia domyślnego lub zatrzymaniu propagacji. te podejścia są bardzo złe, ponieważ zepsują wszelkie inne zdarzenia wywołane w menu rozwijanym (tj. elementy mojej mobilnej formy jquery) przy użyciu tego podejścia pozwala ci konkretnie określić, kiedy samo menu się zamyka i pozwala ci podjąć działania tylko w stosunku do tego wydarzenia. ta odpowiedź wymaga tylu gwiazdek…
webfish

3
@ webfish Ile zajęło Ci skanowanie Internetu? (rofl)
php-dev

2
Może to kiedyś działało ... ale w przypadku bootstrap 4 e.target jest zawsze rozwijanym menu. Nie kliknięty cel. Nawet jeśli klikniesz poza menu rozwijane, e.target nadal będzie rozwijanym menu. Nie możesz więc wykonać tego rodzaju kontroli. Czy ktoś widzi sposób na obejście tego?
FredArters

36

Absolutnie najlepszą odpowiedzią jest umieszczenie znacznika formularza po menu rozwijanym klasy

więc twój kod to

<ul class="dropdown-menu">
  <form>
    <li>
      <div class="menu-item">bla bla bla</div>
    </li>
  </form>
</ul>

2
funkcjonalnie działał wspaniale dla mnie, ale zepsuł styl
2778

2
było to dla mnie najszybsze rozwiązanie
Jonathan Morales Vélez

15
To nie jest najlepsza odpowiedź :) <li>element nie powinien znajdować się w <form> elemencie.
GETah

2
To nie jest poprawne semantycznie rozwiązanie - jedynym prawidłowym dzieckiem UL jest LI - jeśli cokolwiek znaczniki formularza powinny znajdować się wewnątrz znaczników li - ale to może nie pozwolić na pożądane działanie - w każdym razie ul> form> li nie jest poprawne znaczniki
gavgrif

2
Podziękowania dla tego szybkiego rozwiązania
Herman Demsong

27

Znalazłem również rozwiązanie.

Zakładając, że Twitter Bootstrap Componentspowiązane funkcje obsługi zdarzeń są delegowane do documentobiektu, zapętlam dołączone procedury obsługi i sprawdzam, czy zdarzenie delegowane dotyczy bieżącego klikniętego elementu (lub jednego z jego elementów nadrzędnych).

$('ul.dropdown-menu.mega-dropdown-menu').on('click', function(event){
    var events = $._data(document, 'events') || {};
    events = events.click || [];
    for(var i = 0; i < events.length; i++) {
        if(events[i].selector) {

            //Check if the clicked element matches the event selector
            if($(event.target).is(events[i].selector)) {
                events[i].handler.call(event.target, event);
            }

            // Check if any of the clicked element parents matches the 
            // delegated event selector (Emulating propagation)
            $(event.target).parents(events[i].selector).each(function(){
                events[i].handler.call(this, event);
            });
        }
    }
    event.stopPropagation(); //Always stop propagation
});

Mam nadzieję, że pomoże to każdemu, kto szuka podobnego rozwiązania.

Dziękuję wszystkim za pomoc.


1
Łał!!! działało idealnie! Przez tydzień miałem kłopoty, używam mCustomeScrollbar i po kliknięciu w rozwijany pasek przewijania go zamykał, skrypt działał i teraz działa dobrze! Stukrotne dzięki.
eirenaios,

działa świetnie! jak można to rozszerzyć, aby użytkownik mógł nadal naciskać klawisz „ESC” (lub nawet klikać na zewnątrz) na klawiaturze, aby zamknąć DD?
Wujek Iroh

2
@MaggewDotCom Naciśnięcie klawisza ESC powinno nadal działać. To samo dotyczy klikania na zewnątrz ...
php-dev

Jedynym minusem tego rozwiązania jest to, że nie pozwala na zagnieżdżone listy rozwijane (powiedz, że masz dropright wewnątrz listy rozwijanej). Czy istnieje obejście tego przypadku?
sdvnksv

26

To może pomóc:

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

Jest to zdecydowanie najprostsza / najlepsza odpowiedź, jeśli chcesz, aby użytkownik wchodził w interakcję z elementem interfejsu użytkownika obecnym w menu rozwijanym (np. Przyciskami opcji) i nie chcesz, aby menu zamykało się po przełączeniu opcji.
Rob

22
$('body').on("click", ".dropdown-menu", function (e) {
    $(this).parent().is(".open") && e.stopPropagation();
});

Może to działać w każdych warunkach.


powinna to być poprawna odpowiedź, ponieważ wykorzystuje mniej wierszy kodu niż wybraną odpowiedź
Muhammad Omer Aslam

@MuhammadOmerAslam Nah! Ponieważ nie spełnia moich wymagań
php-dev

12

jQuery:

<script>
  $(document).on('click.bs.dropdown.data-api', '.dropdown.keep-inside-clicks-open', function (e) {
    e.stopPropagation();
  });
</script>

HTML:

<div class="dropdown keep-inside-clicks-open">
  <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
     Dropdown Example
    <span class="caret"></span>
  </button>
  <ul class="dropdown-menu">
    <li><a href="#">HTML</a></li>
    <li><a href="#">CSS</a></li>
    <li><a href="#">JavaScript</a></li>
  </ul>
</div>

Próbny :

Ogólne: https://jsfiddle.net/kerryjohnson/omefq68b/1/

Twoje demo z tym rozwiązaniem: http://jsfiddle.net/kerryjohnson/80oLdtbf/101/


9

Próbowałem tej prostej rzeczy i zadziałało to jak urok.

Zmieniłem element menu rozwijanego z <div>na <form>i działało to dobrze.

<div class="nav-item dropdown" >
  <a href="javascript:;" class="nav-link dropdown-toggle" data-toggle="dropdown">
   Click to open dropdown
 </a>
 <form class="dropdown-menu   ">
  <ul class="list-group text-black">
     <li class="list-group-item"  >
     </li>
     <li class="list-group-item"   >
     </li>
  </ul>
</form>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>

<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>


<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"/>


<div class="nav-item dropdown" >
  <a href="javascript:;" class="nav-link dropdown-toggle" data-toggle="dropdown">
   Click to open dropdown
 </a>
 <form class="dropdown-menu   ">
  <ul class="list-group text-black">
     <li class="list-group-item"  >
      List Item 1
     </li>
     <li class="list-group-item"   >
         LI 2<input class="form-control" />
     </li>
     <li class="list-group-item"   >
        List Item 3
     </li>
  </ul>
</form>


6

Mam podobny problem niedawno i próbował różnych sposobów rozwiązania go z usuwaniem danych atrybutu data-toggle="dropdown"i słuchania clickzeevent.stopPropagation() wywołania.

Drugi sposób wygląda lepiej. Korzystają z tego również programiści Bootstrap. W pliku źródłowym znalazłem inicjalizację elementów rozwijanych:

// APPLY TO STANDARD DROPDOWN ELEMENTS
$(document)
.on('click.bs.dropdown.data-api', clearMenus)
.on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
.on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
.on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
.on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
}(jQuery);

Więc ta linia:

.on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })

sugeruje, że możesz umieścić formelement w pojemniku z klasą, .dropdownaby uniknąć zamykania menu rozwijanego.


6

Bootstrap sam rozwiązał ten problem, obsługując <form>tagi w menu rozwijanych. Ich rozwiązanie jest całkiem zrozumiałe i możesz je przeczytać tutaj: https://github.com/twbs/bootstrap/blob/v4-dev/js/src/dropdown.js

Sprowadza się to do zapobiegania propagacji w elemencie dokumentu i robi to tylko dla zdarzeń typu 'click.bs.dropdown.data-api'pasujących do selektora '.dropdown .your-custom-class-for-keep-open-on-click-elements'.

Lub w kodzie

$(document).on('click.bs.dropdown.data-api', '.dropdown .keep-open-on-click', (event) => {
    event.stopPropagation();
});

1
Dziękuję, dziękuję, dziękuję za link do źródła. Dla innych zastanawiających się, dlaczego formpodejście z przykładów nie działa dla Ciebie - korzystałem z klasy dropleft, ale potrzebuje ona również dropdown, aby selektor formularzy pasował.
Mark K Cowan

6

Zmodyfikowałem odpowiedź @ Vartan, aby działała z Bootstrap 4.3. Jego rozwiązanie nie działa już z najnowszą wersją, ponieważ targetwłaściwość zawsze zwraca katalog główny rozwijanego menu, divniezależnie od tego, gdzie kliknięto.

Oto kod:

$('.dropdown-keep-open').on('hide.bs.dropdown', function (e) {
  if (!e.clickEvent) {
    // There is no `clickEvent` property in the `e` object when the `button` (or any other trigger) is clicked. 
    // What we usually want to happen in such situations is to hide the dropdown so we let it hide. 
    return true;
  }

  var target = $(e.clickEvent.target);

  return !(target.hasClass('dropdown-keep-open') || target.parents('.dropdown-keep-open').length);
});
<div class="dropdown dropdown-keep-open">
  <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
    Dropdown button
  </button>
  <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
    <a class="dropdown-item" href="#">Action</a>
    <a class="dropdown-item" href="#">Another action</a>
    <a class="dropdown-item" href="#">Something else here</a>
  </div>
</div>

oneline:$('.dropdown-keep-open').on('hide.bs.dropdown', ev => !(ev.clickEvent && $(ev.target).has(ev.clickEvent.target).length))
Matveev Dmitriy

@MatveevDmitriy Przykro mi, ale nikt, po prostu nikt nie może przeczytać tego jednego linijki. Pisanie kodu w ten sposób jest złą praktyką.
ViRuSTriNiTy

Ostatni wiersz można uprościć za pomocą return !target.closest('.dropdown-keep-open').length). To powiedziawszy, to świetne rozwiązanie! Znalazłem to potrzebne do rozwiązania tego problemu.
patrick3853

6
$('body').on("click", ".dropdown-menu", function (e) {
    $(this).parent().is(".show") && e.stopPropagation();
});

Po pierwsze dziękuję za odpowiedź. Odpowiedź na pytanie jest już udzielona. Mam też inny wymóg, jak opisano w pytaniu, niż wspólny wymóg.
php-dev

4
$('ul.nav.navbar-nav').on('click.bs.dropdown', function(e){
    var $a  = $(e.target), is_a = $a.is('.is_a');
    if($a.hasClass('dropdown-toggle')){   
        $('ul.dropdown-menu', this).toggle(!is_a);
        $a.toggleClass('is_a', !is_a);
    }
}).on('mouseleave', function(){
    $('ul.dropdown-menu',this).hide();
    $('.is_a', this).removeClass('is_a');
});

Zaktualizowałem go jeszcze raz, aby był jak najmądrzejszy i najbardziej funkcjonalny. teraz zamyka się, gdy unosisz się poza nawigacją, pozostając otwartym, gdy jesteś w nim. po prostu perfekcyjny.


Twoje rozwiązanie jest sprytne ze względu na jego krótkość, jednak po dodaniu klasy showmenu rozwijane nie zamyka się po kliknięciu na zewnątrz, a my musimy kliknąć przełącznik rozwijany przed ... W każdym razie +1
php-dev

zaktualizowałem go, spójrz na wersję demonstracyjną. jest to najlepsza przyczyna, aby nie sprawdzać za każdym razem zdarzenia kliknięcia w ciało. wpływa tylko na element wewnątrz każdego elementu nawigacyjnego, a nie poza nim.
Luca Filosofi

Moje rozwiązanie również nie opiera się na bodyzdarzeniu kliknięcia ^^
php-dev

tak, częściowo przekazuje zdarzenie kliknięcia ciała, próbuje sprawdzić, który element został kliknięty podczas delegacji ciała. $('body').on('click', function (e) {
Luca Filosofi,

Nie! To nie moja odpowiedź. Moja odpowiedź jest ostatnia.
php-dev

4

Jak na przykład Bootstrap 4 Alpha ma to wydarzenie w menu. Dlaczego nie użyć?

// PREVENT INSIDE MEGA DROPDOWN
$('.dropdown-menu').on("click.bs.dropdown", function (e) {
    e.stopPropagation();
    e.preventDefault();                
});

1
e.preventDefault();blokuje linki, możesz je pominąć
długi

@czachor masz rację! e.preventDefault (); Uniemożliwiaj linkowi śledzenie adresu URL.
Frank Thoeny,

3

Możesz zatrzymać kliknięcie menu rozwijanego w celu propagacji, a następnie ręcznie zaimplementować kontrolki karuzeli za pomocą metod javascript karuzeli .

$('ul.dropdown-menu.mega-dropdown-menu').on('click', function(event) {
    event.stopPropagation();
});

$('a.left').click(function () {
    $('#carousel').carousel('prev');
});

$('a.right').click(function () {
    $('#carousel').carousel('next');
});

$('ol.carousel-indicators li').click(function (event) {
    var index = $(this).data("slide-to");
    $('#carousel').carousel(index);
});

Oto jsfiddle .


Twój przykład działa dobrze, ale problem polega na tym, że rozwijane menu może zawierać dowolne treści, a nie tylko obrazy karuzeli ...
php-dev

3

Dzięki Angular2 Bootstrap możesz używać nonInput w większości scenariuszy:

<div dropdown autoClose="nonInput">

nonInput - (domyślnie) automatycznie zamyka menu rozwijane po kliknięciu dowolnego z jego elementów - o ile kliknięty element nie jest wejściem ani obszarem tekstowym.

https://valor-software.com/ng2-bootstrap/#/dropdowns


2

Wiem, że to pytanie było specjalnie dla jQuery, ale dla każdego, kto używa AngularJS, który ma ten problem, możesz utworzyć dyrektywę, która to obsługuje:

angular.module('app').directive('dropdownPreventClose', function() {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
          element.on('click', function(e) {
            e.stopPropagation(); //prevent the default behavior of closing the dropdown-menu
          });
        }
    };
});

Następnie po prostu dodaj atrybut dropdown-prevent-closedo elementu, który powoduje zamknięcie menu, i powinno temu zapobiec. Dla mnie był to selectelement, który automatycznie zamykał menu:

<div class="dropdown-menu">
  <select dropdown-prevent-close name="myInput" id="myInput" ng-model="myModel">
    <option value="">Select Me</option>
  </select>
</div>

6
<div class="dropdown-menu" ng-click="$event.stopPropagation()">pracuje dla mnie w 1.2.x
dr3w

2

[Bootstrap 4 Alpha 6] [Railsy] Dla deweloperów Railsów, e.stopPropagation()spowoduje to niepożądane zachowanie link_toz data-methodnie równą, getponieważ domyślnie zwróci wszystkie twoje żądania jako get.

Aby rozwiązać ten problem, proponuję to uniwersalne rozwiązanie

$('.dropdown .dropdown-menu').on('click.bs.dropdown', function() {
  return $('.dropdown').one('hide.bs.dropdown', function() {
    return false;
  });
});


2

Zamiast pisać kod javascript lub jquery (wymyślanie koła na nowo). Powyższym scenariuszem można zarządzać za pomocą opcji automatycznego zamykania bootstrap. Możesz podać jedną z wartości do automatycznego zamykania :

  1. zawsze - (Domyślnie) automatycznie zamyka menu rozwijane po kliknięciu dowolnego z jego elementów.

  2. outsideClick - automatycznie zamyka menu rozwijane tylko wtedy, gdy użytkownik kliknie dowolny element poza menu rozwijanym.

  3. disabled - wyłącza automatyczne zamykanie

Spójrz na następujący plunkr:

http://plnkr.co/edit/gnU8M2fqlE0GscUQtCWa?p=preview

Zestaw

uib-dropdown auto-close="disabled" 

Mam nadzieję że to pomoże :)


5
Należy wyraźnie zaznaczyć, że jest to dobre tylko dla osób używających ui-bootstrap, co prawdopodobnie nie dzieje się tak w przypadku bardzo wielu osób, które oglądają to pytanie.
kevlarr

Dobrze opisałeś, ale myślę, że powinieneś napisać rozwiązanie jako uib-dropdown auto-close="outsideClick". Menu zamykane po kliknięciu w środku jest tylko niewielką niedogodnością, ale menu nie zamykające się po kliknięciu na zewnątrz jest dość denerwujące.
vusan

2

Wiem, że już istnieje poprzednia odpowiedź sugerująca użycie formularza, ale podany znacznik jest nieprawidłowy / idealny. Oto najprostsze rozwiązanie, w ogóle nie wymaga javascript i nie psuje listy rozwijanej. Działa z Bootstrap 4.

<form class="dropdown-item"> <!-- Your elements go here --> </form>


@RosdiKasim Mam to działa dobrze na stronie internetowej z Bootstrap 4.0.0. Nie testowałem z 4.1
Radu Ciobanu,

Właściwie powinno to wyglądać tak: <form class = "dropdown dropdown-item">
Nasser Sadraee

2

To pomogło mi

$('.dropdown-menu').on('click', function (e) {
     if ($(this).parent().is(".open")) {
         var target = $(e.target);
         if (target.hasClass("keepopen") || target.parents(".keepopen").length){
                    return false; 
                }else{
                    return true;
                }
            }            
});

Twój rozwijany element menu musi wyglądać tak: (zwróć uwagę na klasy dropdown-menui keepopen.

<ul role="menu" class="dropdown-menu topmenu-menu eserv_top_notifications keepopen">

Powyższy kod zapobiega wiązaniu całości <body>, zamiast do określonego elementu z klasą dropdown-menu.

Mam nadzieję, że to komuś pomoże.

Dzięki.


Dzięki Zaktualizowano As Bootstrap 4 $ ('. Dropdown-menu [data-handledropdownclose = "true"]'). On ('click', function (e) {if ($ (this) .parent (). Is (" .show ")) {var target = $ (e.target); return (target.hasClass („ CloseDropDown ”) || target.parents („. CloseDropDown ”). długość);}});
Thulasiram

1

Najprostszym działającym rozwiązaniem dla mnie jest:

  • dodawanie keep-openklasy do elementów, które nie powinny powodować zamykania rozwijanego menu
  • a ten fragment kodu zajmie się resztą:
$('.dropdown').on('click', function(e) {
    var target = $(e.target);
    var dropdown = target.closest('.dropdown');
    return !dropdown.hasClass('open') || !target.hasClass('keep-open');
});

czy możesz mi pomóc naprawić ten stackoverflow.com/questions/51552712/... @ Gee-Bee
Zhu

1

Stwierdziłem, że żadne z rozwiązań nie działa tak, jak chciałbym używać domyślnej nawigacji bootstrap. Oto moje rozwiązanie tego problemu:

       $(document).on('hide.bs.dropdown', function (e) {
        if ($(e.currentTarget.activeElement).hasClass('dropdown-toggle')) {
          $(e.relatedTarget).parent().removeClass('open');
          return true;
        }
        return false;
       });

1

W .dropdowntreści umieść .keep-openklasę na dowolnej etykiecie, takiej jak:

$('.dropdown').on('click', function (e) {
    var target = $(e.target);
    var dropdown = target.closest('.dropdown');
    if (target.hasClass('keep-open')) {
        $(dropdown).addClass('keep-open');
    } else {
        $(dropdown).removeClass('keep-open');
    }
});

$(document).on('hide.bs.dropdown', function (e) {
    var target = $(e.target);
    if ($(target).is('.keep-open')) {
        return false
    }
});

W poprzednich przypadkach unikano zdarzeń związanych z obiektami kontenera, teraz kontener dziedziczy klasę utrzymywania otwarcia i sprawdzania przed zamknięciem.


1

Zrobiłem to z tym:

$(element).on({
    'mouseenter': function(event) {
        $(event.currentTarget).data('mouseover', true);
    },
    'mouseleave': function(event) {
        $(event.currentTarget).data('mouseover', false);
    },
    'hide.bs.dropdown': function (event) {
        return !$(event.currentTarget).data('mouseover');
    }
});

0
$(function() {
    $('.mega-dropdown').on('hide.bs.dropdown', function(e) {
        var $target = $(e.target);
        return !($target.hasClass("keep-open") || $target.parents(".keep-open").size() > 0);
    });

    $('.mega-dropdown > ul.dropdown-menu').on('mouseenter', function() {
        $(this).parent('li').addClass('keep-open')
    }).on('mouseleave', function() {
        $(this).parent('li').removeClass('keep-open')
    });
});

0

Aby zamknąć menu rozwijane tylko wtedy, gdy zdarzenie kliknięcia zostało wywołane poza menu rozwijanym ładowania początkowego, działało to dla mnie:

Plik JS:

    $('.createNewElement').on('click.bs.dropdown.data-api', '.tags-btn-group.keep-open-dropdown', function (e) {
        var target = $(e.target);
        if (target.hasClass("dropdown-menu") || target.parents(".dropdown-menu").length) {
            e.stopPropagation();
        }
    });

Plik HTML:

<!-- button: -->
<div class="createNewElement">
                <div class="btn-group tags-btn-group keep-open-dropdown">

                    <div class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">OPEN DROPDOWN</div>

                    <ul class="dropdown-menu">
                        WHAT EVER YOU WANT HERE...
                    </ul>

                </div>
</div>

0

Możesz mieć pewne problemy, jeśli użyjesz metody return false lub stopPropagation (), ponieważ Twoje zdarzenia zostaną przerwane. Wypróbuj ten kod, działa dobrze:

$(function() {
    $('.dropdown').on("click", function (e) {
            $('.keep-open').removeClass("show");
    });
    $('.dropdown-toggle').on("click", function () {
            $('.keep-open').addClass("show");
    });

    $( ".closeDropdown" ).click(function() {
        $('.dropdown').closeDropdown();
    });
});
jQuery.fn.extend({
    closeDropdown: function() {
        this.addClass('show')
            .removeClass("keep-open")
            .click()
            .addClass("keep-open");
    }
  });

W HTML:

<div class="dropdown keep-open" id="search-menu" >
    <button  class="btn dropdown-toggle btn  btn-primary" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
    <i class="fa fa-filter fa-fw"></i> 
    </button>
    <div class="dropdown-menu">
        <button class="dropdown-item" id="opt1" type="button">Option 1</button>
        <button class="dropdown-item" id="opt2" type="button">Option 2</button>
        <button type="button" class="btn btn-primary closeDropdown">Close</button>
    </div>
</div>

Jeśli chcesz zamknąć okno rozwijane:

`$('#search-menu').closeDropdown();`

0

W Bootstrap 4 możesz również to zrobić:

$('#dd-link').on('hide.bs.dropdown', onListHide)

function onListHide(e)
{
  if(e.clickEvent && $.contains(e.relatedTarget.parentNode, e.clickEvent.target)) {
  e.preventDefault()
  }
}

gdzie #dd-linkjest element lub przycisk kotwicy, który ma data-toggle="drowndown"właściwość.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.