Запретить select2 переворачивать раскрывающийся список вверх

согласно заголовку, есть ли способ заставить select2 всегда создавать выпадающий список вместо раскрывающегося списка?

также появляется некоторый javascript, который либо вызывает флип при прокрутке над раскрывающимся списком, добавляя новый класс CSS "select2-drop-above", либо оба.

EDIT: я должен был указать, что я вытаскиваю библиотеку через select2-rails. Я надеюсь, что есть способ обойти это, который не включает в себя вытягивание всего Select2 lib в себя и редактирование select2.JS файл напрямую.

6 ответов


изменение плагина не является предпочтительным, как вы упомянули. У меня была аналогичная проблема и не мог найти способ использовать 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);
        }
    });

этот код определяет, достаточно ли места для размещения выпадающего списка внизу, а если нет, создает его, добавляя margin-bottom к некоторому элементу на странице. Затем он прокручивается чуть выше select2, чтобы раскрывающийся список не перевернулся.


вы можете просто изменить select2.js


Где написано

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

просто измените его на

enoughRoomBelow = true,
enoughRoomAbove = false,

вы можете сделать это, перезаписав CSS так:

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

поскольку изменение исходного кода не является опцией и добавление крючка к select2:open событие не очень элегантно, особенно когда у вас есть несколько экземпляров select2 на одной странице, Я написал небольшое расширение для Select2 плагин.

моя реализация вдохновлена PR из репозитория плагина (https://github.com/select2/select2/pull/4618), который еще не слит.

в основном, следующий код переопределяет исходный функция плагина, которая обрабатывает выпадающее положение и добавляет новую опцию (dropdownPosition), чтобы заставить выпадающее положение выше / ниже.

новая dropdownPosition опция может принимать следующие значения: - below - выпадающий список всегда отображается в нижней части ввода; - above - выпадающий список всегда отображается в верхней части ввода; - 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);

инициализируйте плагин следующим образом:

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

скрипка здесь: https://jsfiddle.net/byxj73ov/

репозиторий Github: https://github.com/andreivictor/select2-dropdownPosition


я использовал, чтобы найти более простое / быстрое решение для этого:

        $("select").select2({

            // Options

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

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

        });

Это просто, вы просто измените .select2-выпадающее меню-выше to .select2-выпадающее меню-ниже на открыть событие (select2:открытая).

Он будет работать только под событием, и может быть много других способов выполнить его просто изменение классов при открытии select.

ps. Это не сработает, если вы попытаетесь заполнить свой select с помощью на jQuery.


обновлено с [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);
            }
        });