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 .

php-dev
źródło
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/

Roma
źródło
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();
});
Arbejdsglæde
źródło
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;
    }
});
Vartan
źródło
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>
Gregory Bowers
źródło
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.

php-dev
źródło
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();
})
Bawantha
źródło
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.

Terry Lin
źródło
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/

Kerry Johnson
źródło
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>

TheVigilant
źródło
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.

Ilya
źródło
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();
});
Daniel Schlaug
źródło
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>
Konrad Kalemba
źródło
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();
});
waza123
źródło
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.

Luca Filosofi
źródło
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();                
});
Frank Thoeny
źródło
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 .

Neil
źródło
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

Nir Soudry
źródło
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>
jtate
źródło
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;
  });
});

Jacky Tong
źródło
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 :)

ashwaniKumar
źródło
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>

Radu Ciobanu
źródło
@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.

Anjana Silva
źródło
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');
});
Gee-Bee
źródło
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;
       });
Mikrofon
źródło
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.

Dixán Santiesteban Feria
źródło
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');
    }
});
William
źródło
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')
    });
});
SNC
źródło
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>
Dudi
źródło
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();`
Hchab
źródło
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ść.

Daniel
źródło