我有一个带有多个文本输入框和一些Select2元素的表单。 使用键盘在字段之间切换可以正常工作- Select2元素行为类似于表单元素,当使用tab键时接收到焦点。 我想知道是否可能在Select2元素获得焦点时打开下拉菜单。
我尝试过以下方法:
$("#myid").select2().on('select2-focus', function(){
$(this).select2('open');
});
但是使用这段代码会导致下拉菜单在进行选择后再次打开。
我有一个带有多个文本输入框和一些Select2元素的表单。 使用键盘在字段之间切换可以正常工作- Select2元素行为类似于表单元素,当使用tab键时接收到焦点。 我想知道是否可能在Select2元素获得焦点时打开下拉菜单。
我尝试过以下方法:
$("#myid").select2().on('select2-focus', function(){
$(this).select2('open');
});
但是使用这段代码会导致下拉菜单在进行选择后再次打开。
以下代码将在初始焦点上打开菜单,但当选择器在菜单关闭后重新聚焦时,不会陷入无限循环。
// on first focus (bubbles up to document), open the menu
$(document).on('focus', '.select2-selection.select2-selection--single', function (e) {
$(this).closest(".select2-container").siblings('select:enabled').select2('open');
});
// steal focus during close - only capture once and stop propogation
$('select.select2').on('select2:closing', function (e) {
$(e.target).data("select2").$selection.one('focus focusin', function (e) {
e.stopPropagation();
});
});
注意:focus
事件会被触发两次
我们可以通过查找焦点事件类型之间的差异来防止无限循环。由于我们只想在最初对控件进行聚焦时打开菜单,因此我们必须以某种方式区分以下抬起事件之间的区别:
以跨浏览器友好的方式做到这一点很困难,因为不同的浏览器发送不同的事件信息,并且Select2已经对其内部事件的触发进行了许多细微的更改,这些更改打断了之前的流程。
一个看起来行之有效的方法是在菜单的closing
事件期间附加事件处理程序,并使用它来捕获即将发生的focus
事件并防止其冒泡到DOM。然后,使用委派监听器,我们将仅在focus
事件完全冒泡到document
时调用实际的聚焦 -> 打开代码。
正如在这个github issue #4025 - Dropdown does not open on tab focus中提到的那样,我们应该检查以确保仅在:enabled
选择元素上调用'open'
,像这样:
$(this).siblings('select<b>:enabled</b>').select2('open');
我们需要对DOM进行一些遍历,因此这里是由Select2生成的HTML结构图:
以下是一些相关的代码片段:
.on('mousedown'
... .trigger('toggle')
.on('toggle'
... .toggleDropdown()
.toggleDropdown
... .open()
.on('focus'
... .trigger('focus'
.on('close'
... $selection.focus()
过去,打开Select2会触发两次,但在问题#3503中已经修复了这个问题,因此应该可以避免一些卡顿现象。
PR #5357似乎破坏了之前在4.05中工作的焦点代码。
$('.select2').select2({});
// on first focus (bubbles up to document), open the menu
$(document).on('focus', '.select2-selection.select2-selection--single', function (e) {
$(this).closest(".select2-container").siblings('select:enabled').select2('open');
});
// steal focus during close - only capture once and stop propogation
$('select.select2').on('select2:closing', function (e) {
$(e.target).data("select2").$selection.one('focus focusin', function (e) {
e.stopPropagation();
});
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.7/css/select2.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.7/js/select2.js"></script>
<select class="select2" style="width:200px" >
<option value="1">Apple</option>
<option value="2">Banana</option>
<option value="3">Carrot</option>
<option value="4">Donut</option>
</select>
已在Chrome、FF、Edge、IE11上进行测试
当前的答案仅适用于3.5.4版本及之前的版本,其中select2触发了模糊和聚焦事件 (select2-focus
& select2-blur
)。它使用$.one
附加一次性使用处理程序来捕获初始焦点,然后在模糊时重新附加它以供后续使用。
$('.select2').select2({})
.one('select2-focus', OpenSelect2)
.on("select2-blur", function (e) {
$(this).one('select2-focus', OpenSelect2)
})
function OpenSelect2() {
var $select2 = $(this).data('select2');
setTimeout(function() {
if (!$select2.opened()) { $select2.open(); }
}, 0);
}
我尝试了@irvin-dominin-aka-edward的两个答案,但也遇到了两个问题(需要点击两次下拉列表和Firefox抛出“事件未定义”)。
我找到了一个解决方案,似乎解决了这两个问题,而且还没有遇到其他问题。这是基于@irvin-dominin-aka-edward的答案,通过修改select2Focus函数,使其不是立即执行代码的其余部分,而是将其包装在setTimeout中。
$('.select2').select2({})
.one('select2-focus', OpenSelect2)
.on("select2-blur", function (e) {
$(this).one('select2-focus', OpenSelect2)
})
function OpenSelect2() {
var $select2 = $(this).data('select2');
setTimeout(function() {
if (!$select2.opened()) { $select2.open(); }
}, 0);
}
body {
margin: 2em;
}
.form-control {
width: 200px;
margin-bottom: 1em;
padding: 5px;
display: flex;
flex-direction: column;
}
select {
border: 1px solid #aaa;
border-radius: 4px;
height: 28px;
}
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/select2/3.5.4/select2.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/select2/3.5.4/select2.js"></script>
<div class="form-control">
<label for="foods1" >Normal</label>
<select id="foods1" >
<option value=""></option>
<option value="1">Apple</option>
<option value="2">Banana</option>
<option value="3">Carrot</option>
<option value="4">Donut</option>
</select>
</div>
<div class="form-control">
<label for="foods2" >Select2</label>
<select id="foods2" class="select2" >
<option value=""></option>
<option value="1">Apple</option>
<option value="2">Banana</option>
<option value="3">Carrot</option>
<option value="4">Donut</option>
</select>
</div>
希望能找到一种适用于页面上所有Select2实例的简单方法。
$(document).on('focus', '.select2', function() {
$(this).siblings('select').select2('open');
});
更新:上述代码似乎在IE11/Select2 4.0.3上无法正常工作。
附言:还添加了过滤器来仅选择单选
字段。带有multiple
属性的选择不需要它,并且如果应用则可能会出现问题。
var select2_open;
// open select2 dropdown on focus
$(document).on('focus', '.select2-selection--single', function(e) {
select2_open = $(this).parent().parent().siblings('select');
select2_open.select2('open');
});
// fix for ie11
if (/rv:11.0/i.test(navigator.userAgent)) {
$(document).on('blur', '.select2-search__field', function (e) {
select2_open.select2('close');
});
}
在选择完成后,可能会触发 select2-focus
事件。
我找到的唯一方法是将 select2-focus
和 select2-blur
事件结合起来,并使用 jQuery 的one
事件处理程序。
因此,当元素首次获得焦点时,由于 one
的原因,select2 只会打开一次,当元素失去焦点时,再次附加一个 one 事件处理程序,依此类推。
代码:
$('#test').select2({
data: [{
id: 0,
text: "enhancement"
}, {
id: 1,
text: "bug"
}, {
id: 2,
text: "duplicate"
}, {
id: 3,
text: "invalid"
}, {
id: 4,
text: "wontfix"
}],
width: "300px"
}).one('select2-focus', select2Focus).on("select2-blur", function () {
$(this).one('select2-focus', select2Focus)
})
function select2Focus() {
$(this).select2('open');
}
示例: http://jsfiddle.net/IrvinDominin/fnjNb/
为了让鼠标单击生效,您必须检查触发处理程序的事件,它只能在事件为focus
时触发open
方法。
代码:
function select2Focus() {
if (/^focus/.test(event.type)) {
$(this).select2('open');
}
}
演示: http://jsfiddle.net/IrvinDominin/fnjNb/4/
select2 v 4.0 改变了其 API 并删除了自定义事件 (见https://github.com/select2/select2/issues/1908)。因此需要改变检测其焦点的方式。
代码:
$('.js-select').select2({
placeholder: "Select",
width: "100%"
})
$('.js-select').next('.select2').find('.select2-selection').one('focus', select2Focus).on('blur', function () {
$(this).one('focus', select2Focus)
})
function select2Focus() {
$(this).closest('.select2').prev('select').select2('open');
}
有点晚了...不过分享一下我使用select2 4.0.0的代码
$("#my_id").select2();
$("#my_id").next(".select2").find(".select2-selection").focus(function() {
$("#my_id").select2("open");
});
$('.my-class').next('.select2').find('.select2-selection').focus(function (e) { $(this).closest('.select2').prev('select..my-class').select2('open'); });
(抱歉,显然不能在评论中换行。) - hackel这里有一个适用于Select2版本4.x的替代解决方案。你可以使用监听器来捕获焦点事件,然后打开选择框。
$('#test').select2({
// Initialisation here
}).data('select2').listeners['*'].push(function(name, target) {
if(name == 'focus') {
$(this.$element).select2("open");
}
});
EventRelay.prototype.bind = function (decorated, container, $container) {
var self = this;
var relayEvents = [
'open', 'opening',
'close', 'closing',
'select', 'selecting',
'unselect', 'unselecting',
'focus'
]};
当焦点发生时,只需要打开select2:
$('#select2').on('select2:focus', function(evt){
$(this).select2('open');
});
在Chrome 54,IE 11,FF 49和Opera 40上运行良好。
KyleMit的答案对我有效(谢谢!),但是我发现,对于允许搜索的select2元素,尝试通过Tab键切换到下一个元素无法使用(Tab顺序实际上丢失了),因此我添加了代码,以便在下拉菜单关闭时将焦点重新设置回主select2元素:
$(document).on('focus', '.select2', function (e) {
if (e.originalEvent) {
var s2element = $(this).siblings('select');
s2element.select2('open');
<b>// Set focus back to select2 element on closing.
s2element.on('select2:closing', function (e) {
s2element.select2('focus');
});</b>
}
});
我尝试了许多方法,最终找到了以下适用于Select2 4.0.1的方法。元素是<select>
元素。
$.data(element).select2.on("focus", function (e) {
$(element).select2("open");
});
我使用的是Select2.full.js版本4.0.3,但以上解决方案都不能正常工作。因此,我结合了上述解决方案。首先,我修改了Select2.full.js文件,将内部的焦点和失去焦点事件转换为jQuery事件,就像"Thomas Molnar"在他的答案中做的那样。
EventRelay.prototype.bind = function (decorated, container, $container) {
var self = this;
var relayEvents = [
'open', 'opening',
'close', 'closing',
'select', 'selecting',
'unselect', 'unselecting',
'focus', 'blur'
];
$("#myId").select2( ... ).one("select2:focus", select2Focus).on("select2:blur", function ()
{
var select2 = $(this).data('select2');
if (select2.isOpen() == false)
{
$(this).one("select2:focus", select2Focus);
}
}).on("select2:close", function ()
{
setTimeout(function ()
{
// Find the next element and set focus on it.
$(":focus").closest("tr").next("tr").find("select:visible,input:visible").focus();
}, 0);
});
function select2Focus()
{
var select2 = $(this).data('select2');
setTimeout(function() {
if (!select2.isOpen()) {
select2.open();
}
}, 0);
}