jQuery 防止 select2 向上翻转下拉菜单

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19983601/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 00:52:51  来源:igfitidea点击:

Prevent select2 from flipping the dropdown upward

javascriptjquerycssjquery-select2select2-rails

提问by kjb

As per title, is there a way to force select2 to always create a dropdown instead of a drop-up?

根据标题,有没有办法强制 select2 始终创建下拉菜单而不是下拉菜单?

There also appears to be some javascript that is either causing the flip when you scroll above the dropdown, adding a new CSS class "select2-drop-above", or both.

似乎还有一些 javascript 在您滚动下拉列表时导致翻转,添加新的 CSS 类“select2-drop-above”,或两者兼而有之。

EDIT: I should've specified that I'm pulling the library in via select2-rails. I'm hoping there is a way around this that doesn't involve pulling the whole select2 lib in myself and editing the select2.js file directly.

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

采纳答案by shanabus

Modifying the plugin is not preferred as you mention. I had a similar issue and couldn't find an way to use select2options to force the dropdown to stay below. The solution I ended up with is the following:

正如您所提到的,不建议修改插件。我遇到了类似的问题,找不到使用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);
        }
    });

This code determines if there is enough room to place the dropdown at the bottom and if not, creates it by adding margin-bottom to some element on the page. It then scrolls to just above the select2 so that the dropdown won't flip.

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

回答by kei

You can just edit select2.js


Where it says

你可以编辑select2.js


它说的地方

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

just change it to

只需将其更改为

enoughRoomBelow = true,
enoughRoomAbove = false,

回答by andreivictor

Since modifying the source code is not an option and adding a hook to the select2:openevent is not very elegant, especially when you have multiple select2 instances in the same page, I have written a small extension for the Select2plugin.

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

My implementation is inspired by a PR from the plugin's repository (https://github.com/select2/select2/pull/4618) that is not yet merged.

我的实现灵感来自尚未合并的插件存储库 ( https://github.com/select2/select2/pull/4618) 中的 PR 。

Basically, the following code overrides the original plugin function that handles the dropdown positioning and adds a new option (dropdownPosition) to force the dropdown positioning above/below.

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

The new dropdownPositionoption can take the following values: - below- the dropdown is always displayed at the bottom of the input; - above- the dropdown is always displayed at the top of the input; - auto(default) - it uses the old behavior.

dropdownPosition选项可以采用以下值: - below- 下拉菜单始终显示在输入的底部;--above下拉菜单总是显示在输入的顶部;- auto(默认) - 它使用旧行为。

Just insert the following code after select2.jsfile:

只需在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);

The initialize the plugin with as follows:

初始化插件如下:

$(document).ready(function() {
  $(".select-el").select2({
    dropdownPosition: 'below'
  });
});

Fiddle here: https://jsfiddle.net/byxj73ov/

在这里小提琴:https: //jsfiddle.net/byxj73ov/

Github repository: https://github.com/andreivictor/select2-dropdownPosition

Github 存储库:https: //github.com/andreivictor/select2-dropdownPosition



UPDATEDecember 30, 2019

2019 年 12 月 30 日更新

Fiddle with the latest Select2 Version (v4.0.12): https://jsfiddle.net/g4maj9ox/

摆弄最新的 Select2 版本 ( v4.0.12): https://jsfiddle.net/g4maj9ox/

回答by Aivus

You can do it by overwriting CSS like so:

您可以通过像这样覆盖 CSS 来实现:

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

回答by Aivus

I used to find an easier/faster solution for that:

我曾经为此找到一个更简单/更快的解决方案:

        $("select").select2({

            // Options

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

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

        });

It's simple, you just change the .select2-dropdown--aboveto .select2-dropdown--belowin the opening event(select2:open).

很简单,您只需在打开事件(select2:open)中将.select2-dropdown--above更改为.select2-dropdown--below

It will only works under the event, and there could be many other ways to perform it just changing classes when the select is opened.

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

ps. It won't work if you try to populate your select using jquery.

附:如果您尝试使用 jquery 填充您的选择,它将不起作用。

回答by aWebDeveloper

Updated from [shanabus] answer

更新自 [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);
            }
        });