避免点击里面的下拉菜单closures

我有一个Twitter的Bootstrap下拉菜单。 正如所有Twitter Bootstrap用户所知道的,下拉菜单在点击时closures(甚至在其内部点击)。

为了避免这种情况,我可以轻松地在下拉菜单上附加一个点击事件处理程序,并简单地添加着名的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> 

这看起来很简单,而且是一个非常常见的行为,而且由于carousel-controls (以及carousel indicators )事件处理程序被委托给document对象,因此这些元素( prev / next控件,…)上的click事件将“忽略不计”。

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

依靠Twitter Bootstrap下拉hide / hidden事件不是一个解决scheme,原因如下:

  • 为两个事件处理程序提供的事件不会引用您单击的元素
  • 下拉菜单的内容是dynamic生成的,所以添加flag类是不可能的

这小提琴是正常的行为, 这个小提琴与event.stopPropagation()添加。

更新

感谢罗马的回答 。 我也find了一个答案,你可以在下面find 。

删除数据属性data-toggle="dropdown"并执行data-toggle="dropdown"的打开/closures可以是一个解决scheme。

首先通过点击链接来打开/closures下拉菜单,如下所示:

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

然后在下拉列表外部听取点击以closures它:

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

这里是演示: http : //jsfiddle.net/RomaLefrancois/hh81rhcm/2/

这也应该有帮助

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

Bootstrap提供以下function:

  | 当隐藏实例方法时立即触发此事件 
 hide.bs.dropdown | 已被调用。 切换的锚点元素是可用的 
                  |  related事件的relatedTarget属性。 

因此,实现这个function应该可以禁用closures下拉菜单。

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

我也find了解决办法。

假设Twitter Bootstrap Components相关的事件处理程序被委托给document对象,我循环附加的处理程序,并检查当前点击元素(或其父母之一)是否由委派的事件。

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

希望它可以帮助任何寻找类似解决scheme的人。

感谢大家的帮助。

绝对最好的答案是在类下拉菜单后面放置一个表单标签

所以你的代码是

 <ul class="dropdown-menu"> <form> <li> <div class="menu-item">bla bla bla</div> </li> </form> </ul> 
 $('body').on("click", ".dropdown-menu", function (e) { $(this).parent().is(".open") && e.stopPropagation(); }); 

这可能适用于任何情况。

  • 演示: http : //jsfiddle.net/4y8tLgcp/
 $('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'); }); 

我已经再次更新,以尽可能最聪明和function。 当您hover在导航之外时,它现在closures,在您进入导航时保持打开状态。 简单完美。

我最近有一个类似的问题,并试图通过删除data属性data-toggle="dropdown"和监听clickevent.stopPropagation()调用解决它的不同方式。

第二种方式看起来更可取。 Bootstrap开发者也使用这种方式。 在源文件中我find了下拉元素的初始化:

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

所以,这一行:

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

build议您可以在类的.dropdown放置一个form元素,以避免closures下拉菜单。

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> 

演示

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

您的演示与此解决scheme: http : //jsfiddle.net/kerryjohnson/80oLdtbf/101/

您可以停止点击传播的下拉列表,然后使用传送带JavaScript方法手动重新实现轮播控件。

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

这是jsfiddle 。

使用Angular2 Bootstrap,您可以在大多数情况下使用nonInput:

 <div dropdown autoClose="nonInput"> 

nonInput – (默认)在单击任何元素时自动closures下拉列表,只要点击的元素不是input或textarea。

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

像例如Bootstrap 4 Alpha有这个菜单事件。 为什么不使用?

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

我知道这个问题是专门针对jQuery,但对于任何使用AngularJS的人都有这个问题,你可以创build一个处理这个问题的指令:

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

然后,只需将属性dropdown-prevent-close到触发菜单closures的元素中,就可以防止它。 对我来说,这是一个自动closures菜单的select元素:

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

我发现没有解决scheme,因为我想使用默认的引导程序导航。 这是我解决这个问题的方法:

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

而不是写一些JavaScript或jQuery代码(重新发明轮子)。 上述场景可以通过引导自动closures选项进行pipe理。 您可以提供以下任一值来自动closures

  1. 总是 – (默认)当点击任何元素时自动closures下拉菜单。

  2. outsideClick – 仅在用户点击下拉菜单之外的任何元素时自动closures下拉菜单。

  3. 禁用 – 禁用自动closures

看看下面的plunkr:

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

 uib-dropdown auto-close="disabled" 

希望这可以帮助 :)

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

对我来说最简单的工作解决scheme是:

  • 向不应导致下拉式closures的元素添加keep-open
  • 其余的代码如下:
 $('.dropdown').on('click', function(e) { var target = $(e.target); var dropdown = target.closest('.dropdown'); return !dropdown.hasClass('open') || !target.hasClass('keep-open'); }); 

[Bootstrap 4 Alpha 6] [Rails]对于Rails开发者, e.stopPropagation()会导致link_todata-method不良行为不相等,因为默认情况下它会将所有的请求作为get返回。

为了解决这个问题,我build议这个解决scheme是普遍的

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

.dropdown内容中,将.keep-open类放在任何标签上,如下所示:

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

前面的例子避免了与容器对象有关的事件,现在容器inheritance了类保持打开状态,并在closures之前检查。

没有别的为我工作,所以我终于做了这个问题,自己解决了这个问题。

这解决了问题,而没有制动别的东西

 $(".navbar").on("click",".megadropdown .dropdown-menu,.megadropdown .dropdown-menu *",function(e){ setTimeout(function(){$(e.target).parents(".dropdown").addClass("open");},50); }); 
 $(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; } }); 

});