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
Prevent select2 from flipping the dropdown upward
提问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 select2
options 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: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.
由于修改源代码不是一个选项,并且给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 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.
新dropdownPosition
选项可以采用以下值: - below
- 下拉菜单始终显示在输入的底部;--above
下拉菜单总是显示在输入的顶部;- auto
(默认) - 它使用旧行为。
Just insert the following code after select2.js
file:
只需在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);
}
});