javascript dropdown - Evita menu a tendina chiudi al clic all'interno




bootstrap html (21)

Ad esempio, Bootstrap 4 Alpha ha questo Evento di menu. Perché non usare?

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

Ho un menu a tendina Bootstrap su Twitter. Come tutti gli utenti di Twitter Bootstrap sanno, il menu a tendina si chiude sul clic (facendo clic anche all'interno di esso).

Per evitare ciò, posso facilmente collegare un gestore di eventi click nel menu a discesa e aggiungere semplicemente il famoso 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>

Questo sembra facile e un comportamento molto comune, tuttavia, e poiché i gestori di eventi di carousel indicators (così come gli carousel indicators ) sono delegati all'oggetto del document , l'evento click su questi elementi (controlli prev / next , ...) sarà “ignorato”.

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

Affidarsi a Twitter Bootstrap dropdown hide / hidden events non è una soluzione per i seguenti motivi:

  • L'evento fornito per entrambi i gestori di eventi non fornisce alcun riferimento all'elemento selezionato
  • Il contenuto del menu a discesa viene generato dinamicamente, quindi non è possibile aggiungere una classe flag

Questo violino è il comportamento normale e questo violino è con event.stopPropagation() aggiunto.

Aggiornare

Grazie a Roman per la sua risposta . Ho anche trovato una risposta che puoi trovare qui sotto .


So che questa domanda era specifica per jQuery, ma per chiunque usi AngularJS che ha questo problema è possibile creare una direttiva che gestisca questo:

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

Quindi aggiungi l'attributo dropdown-prevent-close al tuo elemento che sta attivando il menu per chiuderlo, e dovrebbe prevenirlo. Per me, era un elemento di select che chiudeva automaticamente il menu:

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

So che c'è già una risposta precedente che suggerisce di usare un modulo ma il markup fornito non è corretto / ideale. Ecco la soluzione più semplice, non è necessario alcun javascript e non interrompe il menu a discesa. Funziona con Bootstrap 4.

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


Invece di scrivere un codice javascript o jquery (reinventando la ruota). Lo scenario sopra può essere gestito dall'opzione di chiusura automatica del bootstrap. Puoi fornire uno dei valori alla chiusura automatica :

  1. sempre - (Predefinito) chiude automaticamente il menu a discesa quando viene fatto clic su uno qualsiasi degli elementi.

  2. outsideClick - chiude automaticamente il menu a discesa solo quando l'utente fa clic su un elemento esterno al menu a discesa.

  3. disabilitato - disabilita la chiusura automatica

Dai un'occhiata al seguente plunkr:

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

Impostato

uib-dropdown auto-close="disabled" 

Spero che questo ti aiuti :)


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>

Demo :

Generico: https://jsfiddle.net/kerryjohnson/omefq68b/1/

La tua demo con questa soluzione: http://jsfiddle.net/kerryjohnson/80oLdtbf/101/


$(function() {
var closeble = false;
$('body').on('click', function (e) {
    if (!$(event.target).is("a.dropdown-toggle")) {
        closeble = false;
    }

});
$('.dropdown').on({
    "click": function(event) {
        if ($(event.target).closest('.dropdown-toggle').length) {
            closeble = true;
        } else {
            closeble = false;
        }
    },
    "hide.bs.dropdown": function() {
        return closeble;
    }
});

});


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

La migliore risposta in assoluto è inserire un tag form dopo il menu a discesa della classe

quindi il tuo codice è

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

[Bootstrap 4 Alpha 6] [Rails] Per lo sviluppatore di rails, e.stopPropagation() porterà a comportamenti indesiderati per link_to con data-method diverso da get dato che per impostazione predefinita restituirà tutte le richieste come get .

Per ovviare a questo problema, suggerisco questa soluzione, che è universale

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

$('.dropdown .dropdown-menu').on('click.bs.dropdown', function() {
  return $('.dropdown').one('hide.bs.dropdown', function() {
    return false;
  });
});
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>

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


Per chiudere il menu a discesa solo se un evento click è stato attivato al di fuori del menu a discesa di avvio, questo è ciò che ha funzionato per me:

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

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

Puoi interrompere il clic sul menu a discesa dalla propagazione e quindi reimplementare manualmente i controlli del carosello utilizzando i metodi javascript di carosello .

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

Ecco il jsfiddle .


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

l'ho aggiornato ancora una volta per essere il più intelligente e funzionale possibile. ora si chiude quando si passa il mouse fuori dal nav, rimanendo aperti mentre ci si trova all'interno. semplicemente perfetto.


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

Questo può funzionare per qualsiasi condizione.


Questo potrebbe aiutare:

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

Non ho trovato nessuna delle soluzioni ha funzionato come vorrei utilizzare il bootstrap di default. Ecco la mia soluzione a questo problema:

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

Con Bootstrap Angular2, puoi utilizzare nonInput per la maggior parte degli scenari:

<div dropdown autoClose="nonInput">

nonInput: (predefinito) chiude automaticamente il menu a discesa quando viene fatto clic su uno qualsiasi degli elementi, a condizione che l'elemento su cui si fa clic non sia un input o un'area di testo.

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


Rimozione dei dati di attributo data-toggle="dropdown" e l'implementazione dell'apertura / chiusura del menu a discesa può essere una soluzione.

Innanzitutto gestendo il clic sul link per aprire / chiudere il menu a discesa in questo modo:

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

e quindi ascoltando i clic all'esterno del menu a discesa per chiuderlo in questo modo:

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

Ecco la demo: http://jsfiddle.net/RomaLefrancois/hh81rhcm/2/


La soluzione di lavoro più semplice per me è:

  • aggiungere la classe keep-open agli elementi che non dovrebbero causare la chiusura del menu a discesa
  • e questo pezzo di codice fa il resto:
$('.dropdown').on('click', function(e) {
    var target = $(e.target);
    var dropdown = target.closest('.dropdown');
    return !dropdown.hasClass('open') || !target.hasClass('keep-open');
});

Recentemente ho avuto un problema simile e ho provato diversi modi per risolverlo rimuovendo i dati degli attributi dei data-toggle="dropdown" e ascolto click con event.stopPropagation() .

Il secondo modo sembra più preferibile. Anche gli sviluppatori Bootstrap usano questo modo. Nel file sorgente ho trovato l'inizializzazione degli elementi del menu a discesa:

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

Quindi, questa linea:

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

suggerisce di inserire un elemento del form all'interno del contenitore con class .dropdown per evitare di chiudere il menu a discesa.


Bootstrap fornisce la seguente funzione:

                 | This event is fired immediately when the hide instance method 
hide.bs.dropdown | has been called. The toggling anchor element is available as the 
                 | relatedTarget property of the event.

Pertanto, l'implementazione di questa funzione dovrebbe essere in grado di disabilitare il menu a discesa dalla chiusura.

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

Non penso che quello di cui hai veramente bisogno sia chiudere il menu quando l'utente fa clic all'esterno; ciò di cui hai bisogno è che il menu si chiuda quando l'utente fa clic in qualsiasi punto della pagina. Se si fa clic sul menu o fuori dal menu, dovrebbe chiudersi correttamente?

Non trovando risposte soddisfacenti in alto mi ha spinto a scrivere questo post sul blog l'altro giorno. Per i più pedanti, ci sono un certo numero di trucchi per prendere nota di:

  1. Se alleghi un gestore di eventi click all'elemento body al momento del clic, assicurati di attendere il secondo clic prima di chiudere il menu e di slegare l'evento. Altrimenti l'evento click che ha aperto il menu diventerà visibile all'ascoltatore che deve chiudere il menu.
  2. Se si utilizza event.stopPropogation () su un evento click, nessun altro elemento della pagina può avere una funzionalità click-anywhere-to-close.
  3. Allegare un gestore di eventi click all'elemento body indefinitamente non è una soluzione performante
  4. Confrontando il target dell'evento, e i suoi genitori con il gestore del gestore, si presume che quello che si desidera sia chiudere il menu quando si fa clic su di esso, quando ciò che si vuole veramente è chiuderlo quando si fa clic in qualsiasi punto della pagina.
  5. Ascoltare eventi sull'elemento body renderà il tuo codice più fragile. Styling innocente come questo lo spezzerebbe: body { margin-left:auto; margin-right: auto; width:960px;} body { margin-left:auto; margin-right: auto; width:960px;}




javascript jquery html twitter-bootstrap-3 drop-down-menu