简体   繁体   English

Select2 在焦点上打开下拉菜单

[英]Select2 open dropdown on focus

I have a form with multiple text inputs and some select2 elements.我有一个包含多个文本输入和一些 select2 元素的表单。 Using the keyboard to tab between fields works fine - the Select2 element behaves like a form element and receives focus when tabbing.使用键盘在字段之间进行 Tab 键工作正常 - Select2 元素的行为类似于表单元素并在 Tab 键时接收焦点。 I was wondering if it is possible to open the dropdown when the Select2 element gets focus.我想知道当 Select2 元素获得焦点时是否可以打开下拉列表。

Here's what I've tried so far:这是我迄今为止尝试过的:

$("#myid").select2().on('select2-focus', function(){
     $(this).select2('open');
});

But using this code makes the dropdown to open again after a selection is made.但是使用此代码会使下拉菜单在进行选择后再次打开。

Working Code for v4.0+ *( including 4.0.7) v4.0+ 的工作代码*(包括 4.0.7)

The following code will open the menu on the initial focus, but won't get stuck in an infinite loop when the selection re-focuses after the menu closes.以下代码将在初始焦点上打开菜单,但在菜单关闭后选择重新聚焦时不会陷入无限循环。

// 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();
  });
});

Explanation解释

Prevent Infinite Focus Loop防止无限聚焦循环

Note : The focus event is fired twice注意focus事件被触发两次

  1. Once when tabbing into the field进入该字段时一次
  2. Again when tabbing with an open dropdown to restore focus再次使用打开的下拉菜单进行 Tab 键以恢复焦点时

焦点菜单状态

We can prevent an infinite loop by looking for differences between the types of focus events.我们可以通过查找焦点事件类型之间的差异来防止无限循环。 Since we only want to open the menu on the initial focus to the control, we have to somehow distinguish between the following raised events:由于我们只想在控件的初始焦点上打开菜单,因此我们必须以某种方式区分以下引发的事件:

事件时间线

Doing so it a cross browser friendly way is hard, because browsers send different information along with different events and also Select2 has had many minor changes to their internal firing of events, which interrupt previous flows.以跨浏览器友好的方式这样做是很困难的,因为浏览器会随不同的事件发送不同的信息,而且 Select2 对其内部事件触发进行了许多细微的更改,这会中断之前的流程。

One way that seems to work is to attach an event handler during the closing event for the menu and use it to capture the impending focus event and prevent it from bubbling up the DOM.一种似乎有效的方法是在菜单的closing事件期间附加一个事件处理程序,并使用它来捕获即将发生的focus事件并防止它冒泡 DOM。 Then, using a delegated listener, we'll call the actual focus -> open code only when the focus event bubbles all the way up to the document然后,使用委托的侦听器,我们将调用实际的焦点 -> 仅当focus事件一直冒泡到document时才调用打开代码

Prevent Opening Disabled Selects防止打开禁用的选择

As noted in this github issue #4025 - Dropdown does not open on tab focus , we should check to make sure we only call 'open' on :enabled select elements like this:正如这个 github 问题#4025 - Dropdown 在选项卡焦点上未打开,我们应该检查以确保我们只在:enabled选择元素上调用'open' ,如下所示:

$(this).siblings('select:enabled').select2('open');

Select2 DOM traversal Select2 DOM 遍历

We have to traverse the DOM a little bit, so here's a map of the HTML structure generated by Select2我们要稍微遍历一下 DOM,所以这里是 Select2 生成的 HTML 结构图

选择 2 DOM

Source Code on GitHub GitHub 上的源代码

Here are some of the relevant code sections in play:以下是一些相关的代码部分:

.on('mousedown' ... .trigger('toggle') .on('mousedown' ... .trigger('toggle')
.on('toggle' ... .toggleDropdown() .on('toggle' ... .toggleDropdown()
.toggleDropdown ... .open() .toggleDropdown ... .open()
.on('focus' ... .trigger('focus' .on('focus' ... .trigger('focus'
.on('close' ... $selection.focus() .on('close' ... $selection.focus()

It used to be the case that opening select2 fired twice, but it was fixed in Issue #3503 and that should prevent some jank曾经是这样的情况,打开 select2 会触发两次,但它已在问题 #3503 中修复,这应该可以防止一些卡顿

PR #5357 appears to be what broke the previous focus code that was working in 4.05 PR #5357似乎是破坏了之前在 4.05 中工作的焦点代码的原因

Working Demo in jsFiddle & Stack Snippets: jsFiddle & Stack Snippets 中的工作演示

 $('.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>

Tested on Chrome, FF, Edge, IE11在 Chrome、FF、Edge、IE11 上测试

For Version 3.5.4 (Aug 30, 2015 and earlier)对于版本 3.5.4 (2015 年 8 月 30 日及更早版本)

The current answer is only applicable to versions 3.5.4 and before, where select2 fired blur and focus events ( select2-focus & select2-blur ).当前答案仅适用于 3.5.4 及之前的版本,其中 select2 触发模糊和焦点事件select2-focus & select2-blur )。 It attaches a one-time use handler using $.one to catch the initial focus, and then reattaches it during blur for subsequent uses.它使用$.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);  
}

I tried both of @irvin-dominin-aka-edward's answers, but also ran into both problems (having to click the dropdown twice, and that Firefox throws 'event is not defined').我尝试了@irvin-dominin-aka-edward 的两个答案,但也遇到了两个问题(必须单击下拉列表两次,并且 Firefox 抛出“事件未定义”)。

I did find a solution that seems to solve the two problems and haven't run into other issue yet.我确实找到了一个似乎可以解决这两个问题并且还没有遇到其他问题的解决方案。 This is based on @irvin-dominin-aka-edward's answers by modifying the select2Focus function so that instead of executing the rest of the code right away, wrap it in setTimeout.这是基于@irvin-dominin-aka-edward 的答案,通过修改 select2Focus 函数而不是立即执行其余代码,而是将其包装在 setTimeout 中。

Demo in jsFiddle & Stack Snippets jsFiddle & Stack Snippets 中的演示

 $('.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>

Something easy that would work on all select2 instances on the page.可以在页面上的所有 select2 实例上使用的简单方法。

$(document).on('focus', '.select2', function() {
    $(this).siblings('select').select2('open');
});

UPDATE: The above code doesn't seem to work properly on IE11/Select2 4.0.3更新:上面的代码在IE11/Select2 4.0.3上似乎不能正常工作

PS: also added filter to select only single select fields. PS:还添加了过滤器以仅选择single选择字段。 Select with multiple attribute doesn't need it and would probably break if applied.带有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');
    });
}

Probably after the selection is made a select2-focus event is triggered.可能在进行选择后,会触发select2-focus事件。

The only way I found is a combination of select2-focus and select2-blur event and the jQuery one event handler.我发现的唯一方法是结合select2-focusselect2-blur事件以及 jQuery one事件处理程序。

So the first time the element get the focus, the select2 is opened for one time (because of one), when the element is blurred the one event handler is attached again and so on.所以第一次元素获得焦点时,select2 被打开一次(因为一个),当元素模糊时,one 事件处理程序再次附加,依此类推。

Code:代码:

$('#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');
}

Demo: http://jsfiddle.net/IrvinDominin/fnjNb/演示: http : //jsfiddle.net/IrvinDominin/fnjNb/

UPDATE更新

To let the mouse click work you must check the event that fires the handler, it must fire the open method only if the event is focus要让鼠标单击工作,您必须检查触发处理程序的事件,只有当事件是focus ,它才必须触发open方法

Code:代码:

function select2Focus() {
    if (/^focus/.test(event.type)) {
        $(this).select2('open');
    }
}

Demo: http://jsfiddle.net/IrvinDominin/fnjNb/4/演示: http : //jsfiddle.net/IrvinDominin/fnjNb/4/

UPDATE FOR SELECT2 V 4.0 SELECT2 V 4.0 的更新

select2 v 4.0 has changed its API's and dropped the custom events (see https://github.com/select2/select2/issues/1908 ). select2 v 4.0 已更改其 API 并删除了自定义事件(请参阅https://github.com/select2/select2/issues/1908 )。 So it's necessary change the way to detect the focus on it.所以有必要改变检测焦点的方式。

Code:代码:

$('.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');
}

Demo: http://jsfiddle.net/IrvinDominin/xfmgte70/演示: http : //jsfiddle.net/IrvinDominin/xfmgte70/

a bit late... but to share my code using select2 4.0.0有点晚了……但是要使用 select2 4.0.0 共享我的代码

$("#my_id").select2();
$("#my_id").next(".select2").find(".select2-selection").focus(function() {
    $("#my_id").select2("open");
});

Here is an alternate solution for version 4.x of Select2.这是 Select2 4.x 版的替代解决方案。 You can use listeners to catch the focus event and then open the select.您可以使用侦听器来捕获焦点事件,然后打开选择。

$('#test').select2({
    // Initialisation here
}).data('select2').listeners['*'].push(function(name, target) { 
    if(name == 'focus') {
        $(this.$element).select2("open");
    }
});

Find the working example here based the exampel created by @tonywchen根据@tonywchen 创建的示例在此处找到工作示例

The problem is, that the internal focus event is not transformed to jQuery event, so I've modified the plugin and added the focus event to the EventRelay on line 2063 of Select2 4.0.3:问题是,内部焦点事件未转换为 jQuery 事件,因此我修改了插件并将焦点事件添加到 Select2 4.0.3 的第 2063 行的 EventRelay 中:

EventRelay.prototype.bind = function (decorated, container, $container) {
    var self = this;
    var relayEvents = [
      'open', 'opening',
      'close', 'closing',
      'select', 'selecting',
      'unselect', 'unselecting',
      'focus'
    ]};

Then it is enough to open the select2 when the focus occurs:那么在焦点发生时打开select2就够了:

$('#select2').on('select2:focus', function(evt){
    $(this).select2('open');
});

Works well on Chrome 54, IE 11, FF 49, Opera 40在 Chrome 54、IE 11、FF 49、Opera 40 上运行良好

KyleMit's answer worked for me (thank you!), but I noticed that with select2 elements that allow for searching, trying to tab to the next element wouldn't work (tab order was effectively lost), so I added code to set focus back to the main select2 element when the dropdown is closing: KyleMit 的回答对我有用(谢谢!),但我注意到对于允许搜索的 select2 元素,尝试使用 Tab 键切换到下一个元素是行不通的(Tab 键顺序实际上丢失了),所以我添加了代码来设置焦点当下拉列表关闭时到主 select2 元素:

$(document).on('focus', '.select2', function (e) {
    if (e.originalEvent) {
        var s2element = $(this).siblings('select');
        s2element.select2('open');

        // Set focus back to select2 element on closing. s2element.on('select2:closing', function (e) { s2element.select2('focus'); });
    }
});

I tried a number of these and finally came up with the following that works for me with Select2 4.0.1.我尝试了其中的一些,最后想出了以下适用于 Select2 4.0.1 的方法。 element is the <select> element.元素是<select>元素。

$.data(element).select2.on("focus", function (e) {
    $(element).select2("open");
});

For me using Select2.full.js Version 4.0.3 none of the above solutions was working the way it should be.对于我使用 Select2.full.js 4.0.3 版,上述解决方案都没有按应有的方式工作。 So I wrote a combination of the solutions above.所以我写了上面的解决方案的组合。 First of all I modified Select2.full.js to transfer the internal focus and blur events to jquery events as "Thomas Molnar" did in his answer.首先,我修改了 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'
    ];

And then I added the following code to handle focus and blur and focussing the next element然后我添加了以下代码来处理焦点和模糊以及聚焦下一个元素

$("#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);  
}

I've had the problem which was two pronged:我遇到了两个方面的问题:
1. In a form with multiple select2 elements, the dropdown won't open on tab, and you need to press space key to open it 1. 有多个select2元素的表单,tab下拉不会打开,需要按空格键打开
2. Once you have made a selection, the tabindex won't be honored and you have to manually click on the next input field 2.一旦你做出选择,tabindex将不会被尊重,你必须手动点击下一个输入字段

While the usual suggestions worked, I came up with my own version, since a library script was doing the conversion of normal select to select2, and hence I had no control over this initialization.虽然通常的建议有效,但我想出了我自己的版本,因为库脚本正在将普通 select 转换为 select2,因此我无法控制这个初始化。

Here is the code that worked for me.这是对我有用的代码。

Tab to open标签打开

$(document).on("focus", ".select2", function() {
    $(this).siblings("select").select2("open");
});

Move to next on selection选择时移至下一个

var inputs = $("input,select"); // You can use other elements such as textarea, button etc. 
                                //depending on input field types you have used
$("select").on("select2:close",function(){
    var pos = $(inputs).index(this) + 1;
    var next = $(inputs).eq(pos);
    setTimeout( function() {
        next.focus();
        if (next.siblings(".select2").length) { //If it's a select
            next.select2("open");
        }
    }, 500); //The delay is required to allow default events to occur
});

Hope this helps.希望这会有所帮助。

an important thing is to keep the multiselect open all the time.重要的是保持多选始终打开。 The simplest way is to fire open event on 'conditions' in your code:最简单的方法是根据代码中的“条件”触发打开事件:

<select data-placeholder="Choose a Country..." multiple class="select2-select" id="myList">
    <option value="United States">United States</option>
    <option value="United Kingdom">United Kingdom</option>
    <option value="Afghanistan">Afghanistan</option>
    <option value="Aland Islands">Aland Islands</option>
    <option value="Albania">Albania</option>
    <option value="Algeria">Algeria</option>
</select>

javascript: javascript:

$(".select2-select").select2({closeOnSelect:false});
$("#myList").select2("open");

fiddle: http://jsfiddle.net/xpvt214o/153442/小提琴: http : //jsfiddle.net/xpvt214o/153442/

This worked for me using Select2 v4.0.3这对我有用 Select2 v4.0.3

//Initialize Select2
 jQuery('.js-select').select2();

// Make Select2 respect tab focus
function select2Focus(){
    jQuery(window).keyup(function (e) {
        var code = (e.keyCode ? e.keyCode : e.which);
        if (code == 9 && jQuery('.select2-search__field:focus').length) {
            jQuery('.js-select').select2('open');
        }
    });
}

select2Focus();

Fork of Irvin Dominin's demo: http://jsfiddle.net/163cwdrw/ Irvin Dominin 的分叉演示: http : //jsfiddle.net/163cwdrw/

I tried these solutions with the select2 version 3.4.8 and found that when you do blur , the select2 triggers first select2-close then select2-focus and then select2-blur , so at the end we end up reopening forever the select2.我在 select2 版本 3.4.8 上尝试了这些解决方案,发现当你执行blur ,select2 首先触发select2-close然后select2-focus然后select2-blur ,所以最后我们最终永远重新打开 select2。

Then, my solution is this one:然后,我的解决方案是这样的:

$('#elemId').on('select2-focus', function(){
    var select2 = $(this).data('select2');
    if( $(this).data('select2-closed') ){
        $(this).data('select2-closed', false)
        return
    }
    if (!select2.opened()) {
        select2.open()
    }
}).on('select2-close', function(){
    $(this).data('select2-closed', true)
})

Somehow select2Focus didn't work here with empty selection, couldn't figured out the issue, therefore I added manual control when after focus event auto open get's triggered.不知何故,select2Focus 在空选择时不起作用,无法解决问题,因此我在触发焦点事件自动打开获取时添加了手动控制。

Here is coffeescript:这是咖啡脚本:

$("#myid").select2()
  .on 'select2-blur', ->
    $(this).data('select2-auto-open', 'true')
  .on 'select2-focus', ->
    $(this).data('select2').open() if $(this).data('select2-auto-open') != 'false'
  .on 'select2-selecting', ->
    $(this).data('select2-auto-open', 'false')

I've tried a pretty ugly solution but it fixed my problem.我尝试了一个非常丑陋的解决方案,但它解决了我的问题。

    var tabPressed = false;

    $(document).keydown(function (e) {
        // Listening tab button.
        if (e.which == 9) {
            tabPressed = true;
        }
    });

    $(document).on('focus', '.select2', function() {
        if (tabPressed) {
            tabPressed = false;
            $(this).siblings('select').select2('open');
        }
    });

You can use this :你可以使用这个:

 $(document).on('select2:open', () => {
    document.querySelector('.select2-search__field').focus();
  });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM