Javascript 防止select2向上翻转下拉列表

Javascript 防止select2向上翻转下拉列表,javascript,jquery,css,jquery-select2,select2-rails,Javascript,Jquery,Css,Jquery Select2,Select2 Rails,根据标题,是否有办法强制select2始终创建下拉列表而不是下拉列表 当你在下拉列表上方滚动时,似乎还有一些javascript导致了翻转,或者添加了一个新的CSS类“select2 drop Up”,或者两者兼而有之 编辑:我应该指定通过select2 rails将库拉入。我希望有一种方法可以解决这个问题,而不需要我自己拉整个select2库,直接编辑select2.js文件。你可以编辑select2.js 上面写着 enoughRoomBelow = dropTop + dropHei

根据标题,是否有办法强制select2始终创建下拉列表而不是下拉列表

当你在下拉列表上方滚动时,似乎还有一些javascript导致了翻转,或者添加了一个新的CSS类“select2 drop Up”,或者两者兼而有之

编辑:我应该指定通过select2 rails将库拉入。我希望有一种方法可以解决这个问题,而不需要我自己拉整个select2库,直接编辑select2.js文件。

你可以编辑
select2.js



上面写着

enoughRoomBelow = dropTop + dropHeight <= viewportBottom,
enoughRoomAbove = (offset.top - dropHeight) >= this.body().scrollTop(),

如你所说,修改插件不是首选。我遇到了类似的问题,无法找到使用
select2
选项强制下拉列表停留在下方的方法。我最终得到的解决方案如下:

$("#mySelect2").select2({ ...options... })
    .on('select2-open', function() {

        // however much room you determine you need to prevent jumping
        var requireHeight = 600;
        var viewportBottom = $(window).scrollTop() + $(window).height();

        // figure out if we need to make changes
        if (viewportBottom < requireHeight) 
        {           
            // determine how much padding we should add (via marginBottom)
            var marginBottom = requireHeight - viewportBottom;

            // adding padding so we can scroll down
            $(".aLwrElmntOrCntntWrppr").css("marginBottom", marginBottom + "px");

            // animate to just above the select2, now with plenty of room below
            $('html, body').animate({
                scrollTop: $("#mySelect2").offset().top - 10
            }, 1000);
        }
    });
$(“#mySelect2”)。选择2({…选项…})
.on('select2-open',function(){
//无论您决定需要多大的空间来防止跳跃
var要求重量=600;
var viewportBottom=$(窗口).scrollTop()+$(窗口).height();
//弄清楚我们是否需要做出改变
如果(视口底部<所需高度)
{           
//确定我们应该添加多少填充(通过marginBottom)
var marginBottom=requireHeight-viewportBottom;
//添加填充,以便向下滚动
$(.alwrelmntorcntwrpr”).css(“marginBottom”,marginBottom+“px”);
//将动画设置在select2上方,下面有足够的空间
$('html,body')。设置动画({
scrollTop:$(“#mySelect2”).offset().top-10
}, 1000);
}
});

此代码确定是否有足够的空间将下拉列表放置在底部,如果没有,则通过向页面上的某些元素添加边距底部来创建下拉列表。然后滚动到select2的正上方,这样下拉列表就不会翻转。

根据[shanabus]答案更新

jQuery("#line_item").select2({
            formatResult: Invoice.formatLineItem
        })
        .on('select2-open', function() {
            // however much room you determine you need to prevent jumping
            var requireHeight = $("#select2-drop").height()+10;
            var viewportBottom = $(window).height() - $("#line_item").offset().top;

            // figure out if we need to make changes
            if (viewportBottom < requireHeight)
            {
                // determine how much padding we should add (via marginBottom)
                var marginBottom = requireHeight - viewportBottom;

                // adding padding so we can scroll down
                $(".aLwrElmntOrCntntWrppr").css("marginBottom", marginBottom + "px");

                // animate to just above the select2, now with plenty of room below
                $('html, body').animate({
                    scrollTop: $("#select2-drop").offset().top - 10
                }, 1000);
            }
        });
jQuery(“#行#u项”)。选择2({
formatResult:Invoice.formatLineItem
})
.on('select2-open',function(){
//无论您决定需要多大的空间来防止跳跃
var requireHeight=$(“#选择2下拉”).height()+10;
var viewportBottom=$(窗口).height()-$(“#line_item”).offset().top;
//弄清楚我们是否需要做出改变
如果(视口底部<所需高度)
{
//确定我们应该添加多少填充(通过marginBottom)
var marginBottom=requireHeight-viewportBottom;
//添加填充,以便向下滚动
$(.alwrelmntorcntwrpr”).css(“marginBottom”,marginBottom+“px”);
//将动画设置在select2上方,下面有足够的空间
$('html,body')。设置动画({
滚动顶部:$(“#选择2下拉”).offset().top-10
}, 1000);
}
});

我过去常常找到一个更简单/更快的解决方案:

        $("select").select2({

            // Options

        }).on('select2:open',function(){

            $('.select2-dropdown--above').attr('id','fix');
            $('#fix').removeClass('select2-dropdown--above');
            $('#fix').addClass('select2-dropdown--below');

        });
很简单,您只需将打开事件中上方的.select2下拉菜单更改为打开事件中下方的(select2:open)

它只在事件下工作,并且可能有许多其他方法来执行它,只要在打开select时更改类即可


另外,如果您试图使用jquery填充select,它将不起作用。

您可以通过如下方式覆盖CSS:

.select-dropdown {
  position: static;
}
.select-dropdown .select-dropdown--above {
      margin-top: 336px;
}

由于修改源代码不是一个选项,而向
select2:open
事件添加钩子也不是很优雅,特别是当您在同一页面中有多个select2实例时,我为
select2
插件编写了一个小扩展

我的实现灵感来自插件库()中尚未合并的PR

基本上,下面的代码覆盖了处理下拉定位的原始插件函数,并添加了一个新选项(
dropdownPosition
)来强制将下拉定位在上方/下方

新的
dropdownPosition
选项可以采用以下值: -
下方
-下拉列表始终显示在输入的底部; -
以上
-下拉列表始终显示在输入的顶部; -
auto
(默认)-它使用旧的行为

只需在
select2.js
文件后插入以下代码:

(function($) {

  var Defaults = $.fn.select2.amd.require('select2/defaults');

  $.extend(Defaults.defaults, {
    dropdownPosition: 'auto'
  });

  var AttachBody = $.fn.select2.amd.require('select2/dropdown/attachBody');

  var _positionDropdown = AttachBody.prototype._positionDropdown;

  AttachBody.prototype._positionDropdown = function() {

    var $window = $(window);

    var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above');
    var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below');

    var newDirection = null;

    var offset = this.$container.offset();

    offset.bottom = offset.top + this.$container.outerHeight(false);

    var container = {
        height: this.$container.outerHeight(false)
    };

    container.top = offset.top;
    container.bottom = offset.top + container.height;

    var dropdown = {
      height: this.$dropdown.outerHeight(false)
    };

    var viewport = {
      top: $window.scrollTop(),
      bottom: $window.scrollTop() + $window.height()
    };

    var enoughRoomAbove = viewport.top < (offset.top - dropdown.height);
    var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height);

    var css = {
      left: offset.left,
      top: container.bottom
    };

    // Determine what the parent element is to use for calciulating the offset
    var $offsetParent = this.$dropdownParent;

    // For statically positoned elements, we need to get the element
    // that is determining the offset
    if ($offsetParent.css('position') === 'static') {
      $offsetParent = $offsetParent.offsetParent();
    }

    var parentOffset = $offsetParent.offset();

    css.top -= parentOffset.top
    css.left -= parentOffset.left;

    var dropdownPositionOption = this.options.get('dropdownPosition');

    if (dropdownPositionOption === 'above' || dropdownPositionOption === 'below') {
      newDirection = dropdownPositionOption;
    } else {

      if (!isCurrentlyAbove && !isCurrentlyBelow) {
        newDirection = 'below';
      }

      if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) {
        newDirection = 'above';
      } else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) {
        newDirection = 'below';
      }

    }

    if (newDirection == 'above' ||
    (isCurrentlyAbove && newDirection !== 'below')) {
        css.top = container.top - parentOffset.top - dropdown.height;
    }

    if (newDirection != null) {
      this.$dropdown
        .removeClass('select2-dropdown--below select2-dropdown--above')
        .addClass('select2-dropdown--' + newDirection);
      this.$container
        .removeClass('select2-container--below select2-container--above')
        .addClass('select2-container--' + newDirection);
    }

    this.$dropdownContainer.css(css);

  };

})(window.jQuery);
在这里拉小提琴:

Github存储库:


更新2019年12月30日

摆弄最新的Select2版本(v4.0.12):

看起来,在CSS中自动强制设置底部值也可以做到这一点。我使用了下面的代码,对我来说效果不错

.my_select_picker_trigger.dropup .dropdown-menu {
    bottom: auto !important;
}

但这意味着您在将来升级select2时必须牢记这一点。所以要小心。你永远不应该修改源脚本,否则会出现问题。不幸的是,这是我唯一能解决问题的方法(使用ajax查询和关闭select)。已创建PR以解决此问题,但尚未合并:不适用于我:(另一种方法可行,但不是这样。原因可能是什么?解决方案可行,但我强烈同意@cmfolio。相反,应该有人以
enoughroomover:true/false
作为插件配置选项来提出拉取请求。让我抓住机会:)。谢谢。我不确定你的意思,它在Chrome中对我正常工作。我正在使用的版本是4.0,而这个版本仍然是3。我已经修复了。select2不工作,因为它添加了一些带有顶级值的内联css。不可能在相关元素上有一个内联顶级值。我尝试做这种事情时摔断了手指,我不确定我是怎么做到的没用,没有理论。我是通过尝试实现的。这不是我尝试过你的理论。也许看看最新版本。它增加了顶级内联值
$(document).ready(function() {
  $(".select-el").select2({
    dropdownPosition: 'below'
  });
});
.my_select_picker_trigger.dropup .dropdown-menu {
    bottom: auto !important;
}