防止select2向下翻转下拉列表

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

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

编辑:我应该指定我通过select2-rails拉动库。 我希望有一种解决方法,不涉及在我自己拉动整个select2 lib并直接编辑select2.js文件。

正如您所提到的,修改插件并不是首选。 我有一个类似的问题,无法找到一种方法来使用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:open事件不是很优雅,特别是当你在同一个页面中有多个select2实例时,我已经为Select2插件编写了一个小扩展。

我的实现受到来自插件存储库( https://github.com/select2/select2/pull/4618 )的PR的启发,该存储库尚未合并。

基本上,以下代码会覆盖处理下拉列表定位的原始插件函数,并添加一个新选项( 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-dropdown – 上面.select2-dropdown –更改为打开事件 (select2:open) 下面的.select2-dropdown

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

PS。 如果您尝试使用jquery填充select,它将无法工作。

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