Prevent select2 from flipping the dropdown upward

前端 未结 6 1724
难免孤独
难免孤独 2020-12-13 09:55

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

There also appears to be some javascript that is either causing the f

6条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2020-12-13 10:14

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

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

    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.

    The new dropdownPosition option 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.

    Just insert the following code after select2.js file:

    (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/

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


    UPDATE December 30, 2019

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

提交回复
热议问题