选择2打开焦点对话框

时间:2014-01-08 07:29:26

标签: jquery jquery-select2

我有一个包含多个文本输入和一些select2元素的表单。 使用键盘在字段之间切换工作正常 - Select2元素的行为类似于表单元素,并在Tab键时获得焦点。 我想知道当Select2元素获得焦点时是否可以打开下拉列表。

这是我到目前为止所尝试的内容:

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

但是使用此代码会在选择后再次打开下拉列表。

17 个答案:

答案 0 :(得分:26)

对于Version 3.5.4 (2015年8月30日及之前)

目前的答案仅适用于版本3.5.4及之前,其中select2已解雇blur and focus eventsselect2-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中。

Demo in 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>

答案 1 :(得分:21)

v4.0的工作代码+ *(包括4.0.7)

以下代码将打开初始焦点上的菜单,但在菜单关闭后选择重新聚焦时不会陷入无限循环。

// 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事件被解雇两次

  1. 一旦进入战场
  2. 再次使用打开的下拉列表进行标记以恢复焦点时
  3. focus menu states

    我们可以通过查找焦点事件类型之间的差异来防止无限循环。由于我们只想在控件的初始焦点上打开菜单,我们必须以某种方式区分以下引发的事件:

    event timeline

    这样做是一种跨浏览器友好的方式很难,因为浏览器会发送不同的信息以及不同的事件,而且Select2对其内部触发事件进行了许多微小的更改,这会中断先前的流量。

    似乎有效的一种方法是在菜单的closing事件期间附加事件处理程序,并使用它来捕获即将发生的focus事件并防止它冒泡DOM。然后,使用委托的侦听器,我们将调用实际焦点 - &gt;仅当focus事件一直到document

    时才会打开代码

    防止打开禁用选择

    正如此github问题#4025 - Dropdown does not open on tab focus中所述,我们应该检查以确保我们只在'open'上选择:enabled这样的选择元素:

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

    Select2 DOM遍历

    我们必须稍微遍历DOM,所以这里是Select2生成的HTML结构的地图

    Select2 DOM

    GitHub上的源代码

    以下是一些相关的代码部分:

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

    曾经是打开select2两次开火的情况,但它已在Issue #3503中修复,这应该会阻止一些jank

    PR #5357似乎打破了之前在4.05中工作的焦点代码

    Working Demo in jsFiddle&amp; 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>

    在Chrome,FF,Edge,IE11上测试

答案 2 :(得分:20)

对于页面上的所有select2实例都可以轻松实现。

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

更新 IE11 / Select2 4.0.3 上面的代码似乎无法正常运行

PS:还添加了过滤条件,仅选择single个选择字段。选择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');
    });
}

答案 3 :(得分:17)

选择完成后,可能会触发select2-focus事件。

我找到的唯一方法是select2-focusselect2-blur事件以及jQuery one事件处理程序的组合。

因此第一次元素获得焦点时,select2会打开一次(因为一个),当元素模糊时,会再次附加一个事件处理程序,依此类推。

代码:

$('#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/

更新

要让鼠标点击工作,您必须检查触发处理程序的事件,它必须仅在事件为open时触发focus方法

代码:

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

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

SELECT2 V 4.0更新

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

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

答案 4 :(得分:9)

有点晚了......但是要使用select2 4.0.0分享我的代码

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

答案 5 :(得分:6)

这是Select2版本4.x的替代解决方案。您可以使用侦听器捕获焦点事件,然后打开选择。

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

根据@tonywchen

创建的示例找到工作示例here

答案 6 :(得分:4)

问题是,内部焦点事件没有转换为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'
    ];

然后在焦点发生时打开select2就足够了:

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

适用于Chrome 54,IE 11,FF 49,Opera 40

答案 7 :(得分:4)

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

答案 8 :(得分:3)

我尝试了其中一些,最后提出了以下适合我的Select2 4.0.1。 element是<select>元素。

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

答案 9 :(得分:3)

对于我使用Select2.full.js版本4.0.3,以上解决方案都没有按照应有的方式工作。 所以我写了上面的解决方案的组合。 首先,我修改了Select2.full.js以将内部焦点和模糊事件转移到jquery事件,如#34; Thomas Molnar&#34;在他的回答中做了。

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

答案 10 :(得分:2)

重要的是要始终保持多选的开放状态。最简单的方法是在代码中的'条件'上触发打开事件:

<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:

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

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

答案 11 :(得分:1)

这对我使用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();

Irvin Dominin的演示分析:http://jsfiddle.net/163cwdrw/

答案 12 :(得分:1)

我遇到了双管齐下的问题:
 1.在具有多个select2元素的表单中,下拉菜单不会在选项卡上打开,您需要按空格键才能打开它  2.完成选择后,tabindex不会被尊重,您必须手动点击下一个输入字段

虽然通常的建议有效,但我提出了自己的版本,因为库脚本正在将普通选择转换为select2,因此我无法控制此初始化。

这是适用于我的代码。

要打开的标签

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

在选择

上移至 next
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
});

希望这有帮助。

答案 13 :(得分:0)

我尝试过一个非常难看的解决方案,但它解决了我的问题。

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

答案 14 :(得分:0)

不知何故,select2Focus在这里没有选择空白,无法解决问题,因此我在焦点事件自动打开后触发了手动控制。

这是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')

答案 15 :(得分:0)

我使用select2版本3.4.8尝试了这些解决方案,并发现当您执行blur时,select2首先触发select2-close然后select2-focus然后触发select2-blur,最后我们终于重新开启了select2。

然后,我的解决方案就是这个:

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

答案 16 :(得分:0)

你可以使用这个:

sys.argv