bootstrap下拉菜单根据屏幕位置自动下拉?

时间:2014-01-20 11:21:56

标签: jquery css twitter-bootstrap twitter-bootstrap-3

我想知道你们中是否有人有我要求准备的东西,以免我摆脱困境。我正在寻找的是一个下拉菜单,根据它在屏幕上的位置自动添加dropup类 - 当用户滚动或调整窗口大小时也会自动更改。

我正在寻找的内容已经在bootstrap-select插件中实现,但该插件太“重”而无法使用。

7 个答案:

答案 0 :(得分:20)

有点晚了,但因为与其他人完全不同,这是我的bootstrap 3解决方案。它全局适用于页面上的所有下拉菜单,也包括动态创建或加载的下拉列表。

请注意,我必须使用shown.bs.dropdown事件,因为尺寸仅在此时准备就绪。

$(document).on("shown.bs.dropdown", ".dropdown", function () {
    // calculate the required sizes, spaces
    var $ul = $(this).children(".dropdown-menu");
    var $button = $(this).children(".dropdown-toggle");
    var ulOffset = $ul.offset();
    // how much space would be left on the top if the dropdown opened that direction
    var spaceUp = (ulOffset.top - $button.height() - $ul.height()) - $(window).scrollTop();
    // how much space is left at the bottom
    var spaceDown = $(window).scrollTop() + $(window).height() - (ulOffset.top + $ul.height());
    // switch to dropup only if there is no space at the bottom AND there is space at the top, or there isn't either but it would be still better fit
    if (spaceDown < 0 && (spaceUp >= 0 || spaceUp > spaceDown))
      $(this).addClass("dropup");
}).on("hidden.bs.dropdown", ".dropdown", function() {
    // always reset after close
    $(this).removeClass("dropup");
});

如果需要,可以使用@PeterWone's app height魔法轻松改进它,目前这对我来说效果很好。

更新

这是代表这个解决方案的小提琴:http://jsfiddle.net/3s2efe9u/

答案 1 :(得分:10)

我在大页面上提供的答案存在性能问题。

我通过使用getBoundingClientRect()并将新类添加到包含dropdows的特定.btn-group来“改进”它。 btn-group-dropup

您的里程可能会有所不同。

(function() {
  // require menu height + margin, otherwise convert to drop-up
  var dropUpMarginBottom = 100;

  function dropUp() {
    var windowHeight = $(window).height();
    $(".btn-group-dropup").each(function() {
      var dropDownMenuHeight, 
          rect = this.getBoundingClientRect();
      // only toggle menu's that are visible on the current page
      if (rect.top > windowHeight) {
        return;
      }
      // if you know height of menu - set on parent, eg. `data-menu="100"`
      dropDownMenuHeight = $(this).data('menu');
      if (dropDownMenuHeight == null) {
        dropDownMenuHeight = $(this).children('.dropdown-menu').height();
      }
      $(this).toggleClass("dropup", ((windowHeight - rect.bottom) < (dropDownMenuHeight + dropUpMarginBottom)) && (rect.top > dropDownMenuHeight));
    });
  };

  // bind to load & scroll - but debounce scroll with `underscorejs`
  $(window).bind({
    "resize scroll touchstart touchmove mousewheel": _.debounce(dropUp, 100),
    "load": dropUp
  });

}).call(this);

答案 2 :(得分:6)

编辑201年1月07日:整理变量名称并稍微优化代码。

dropup = function() {
  $(".dropdown-toggle").each(function(){ 
    offsetTop=$(this).offset().top+$(this).height()-$(window).scrollTop();           
    offsetBottom=$(window).height()-$(this).height()-$(this).offset().top+$(window).scrollTop();
    ulHeight=$(this).parents('.btn-group').find('ul').height();

    if ((offsetBottom < ulHeight) && (offsetTop > ulHeight)) {
      parent.addClass('dropup');
    } else {
      parent.removeClass('dropup');
    }
  });
} 

$(window).on('load resize scroll', dropup);

答案 3 :(得分:3)

我知道这是一个老问题,但谷歌搜索结果很高,所以这是另一个对我有用的简单解决方案。调整150语句中的if,无论您的下拉列表需要多大空间。

var dropUp = function() {
    var windowHeight = $(window).innerHeight();
    var pageScroll = $('body').scrollTop();

    $( ".your-dropdown" ).each( function() {
        var offset = $( this ).offset().top;
        var space = windowHeight - ( offset - pageScroll );

        if( space < 150 ) {
            $( this ).addClass( "dropup" );
        } else  {
            $( this ).removeClass( "dropup" );
        }
    });
}

$(window).load(dropUp);
$(window).bind('resize scroll mousewheel', dropUp);

答案 4 :(得分:2)

为什么不采用JIT方法,而不是每次更改剪辑边界时都会调整每个菜单?

<body>
  <div id="viewport-proxy" style="visibility:hidden; 
    position:absolute; height:100%; width:100%; margin:0; padding:0; 
    top:0; left: 0; right:0; bottom:0;"></div>
...

var w = window, d = document, e = d.documentElement;
var g = d.getElementsByTagName('body')[0];
function appHeight() { 
  var a = w.innerHeight || e.clientHeight || g.clientHeight;
  var b = $("#viewport-proxy").height();
  return a < b ? a : b;
};

$(".dropdown").on('show.bs.dropdown', function () {
    var windowHeight = appHeight();
    var rect = this.getBoundingClientRect();
    if (rect.top > windowHeight) return;
    var menuHeight = $(this).children('.dropdown-menu').height();
    $(this).toggleClass("dropup", 
      ((windowHeight - rect.bottom) < menuHeight) && 
      (rect.top > menuHeight));
  });

显然,您必须在菜单来去时管理事件绑定。在Nathan的答案演变为上面的Durandal应用程序中,每行代表一个数据的上下文菜单。我在数据加载上创建绑定,将它们保存在视图模型中并在停用时销毁它们。我不需要在激活时重新创建它们,因为它会调用数据加载例程,从而创建绑定。

我还补充说:

$(window).on("scroll resize", function () { $(".dropdown.open").dropdown("toggle"); });

你把它放在shell.js中,所以它早期加载并影响所有视图。如果它还不是很明显,那么当窗口滚动或调整大小时,它会关闭任何打开的dropup。这符合Windows约定,因此无需在调整大小或滚动事件时重新计算定位。

注意appHeight功能。即使jQuery无法准确报告手机上的窗口高度,但appHeight在我到目前为止测试的每个平台和浏览器上都能正常工作(IE,Ch,FF桌面,IE,Ch,Sa移动)。

在目前的版本中,它测量一个绝对定位的隐藏div集来填充视口。这适用于Android Chrome但不适用于IE,而代码中显示的其他方法适用于IE但不适用于Android Chrome,因此我使用两者并使用较低的数字。

在我的Durandal应用程序中,该函数在app对象上实现为高度方法,但为了简洁明了,我将示例代码展平。

答案 5 :(得分:0)

我发现ZoltánTamási的答案是一个很好的起点,但是当下拉列表出现在带有垂直滚动条的div中时,我的答案还不够。我需要该div的高度(下面代码中的scrollHeight变量)来确定下拉列表是否会占用底部的大量空间。

jquery(document).on("show.bs.dropdown", ".dropdown", function () {
  var $ul = jquery(this).children(".dropdown-menu");
  var menuHeight = $ul.height()
  var buttonHeight = jquery(this).children(".dropdown-toggle").height();
  var scrollHeight = $ul.parent().offsetParent().height();
  var menuAnchorTop = $ul.parent().position().top + buttonHeight;

  // how much space would be left at the top
  var spaceUp = (menuAnchorTop - buttonHeight - menuHeight);
  // how much space would be left at the bottom
  var spaceDown = scrollHeight - (menuAnchorTop + menuHeight);
  // Switch to dropup if more space there
  if (spaceDown < 0 && (spaceUp >= 0 || spaceUp > spaceDown))
    jquery(this).addClass("dropup");
}).on("hidden.bs.dropdown", ".dropdown", function() {
  // always reset after close
  jquery(this).removeClass("dropup");
});

答案 6 :(得分:0)

我已经检查了性能和浏览器支持(chrome,Firefox,Edge,IE 10及更高版本)。

我已经介绍了垂直和水平自动定位。

代码:

   <aura:iteration items="{!v.lstcon}" var="objWrap" indexVar="ind">
        <tr class="slds-hint-parent">
            <td data-label="Account Name">
                <div class="slds-truncate" >
                    <lightning:input class="{!ind+' '+'slds-show'}" 
    type="checkbox" name="input1" value="{!objWrap.isSelected}" 
     aura:id="checkedbox" onchange="{!c.selectone}"/>
                </div>