标签选择Select2输入时选择当前项目

时间:2018-03-03 21:08:36

标签: javascript jquery jquery-select2 jquery-select2-4

这是以下类似的 SO问题和几个github问题的主题,包括:

建议的解决方案或问题同等地处理了所有模糊事件,无论它们是如何被调用的。大多数答案都会通过设置Automatic selection来充分利用selectOnClose

理想情况下,仅在鼠标悬停在选项上后单击下拉列表(转义)不应更改值:

SelectOnClose violation of principle of least surprise

如何更新tabout上的选择,而不是其他关闭事件?

这里是jsFiddle和StackSnippets中的MCVE:



$('.select2').select2({});

<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/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.0/js/select2.js"></script>

<div class="form-control">
  <label for="foods2">Select2</label>
  <select id="foods2" class="select2" >
    <option value="1">Apple</option>
    <option value="2">Banana</option>
    <option value="3">Carrot</option>
    <option value="4">Donut</option>
  </select>
</div>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:1)

通过修改同样处理制表符和esc键的原始source code on line 323,可以轻松处理这个问题:

if (key === KEYS.ESC || key === KEYS.TAB || (key === KEYS.UP && evt.altKey)) {
    self.close();
    evt.preventDefault();
}

但理想情况下,第三方库应该使用拉取请求进行修改。因此,我们在为此创建包装器时遇到了一些问题。原则上,检测标签 keypress事件 hard 。如果我们抓得太晚,另一个动作可能会取代它,或者可能会在另一个领域被解雇。

捕获标签事件和持久信息的前景似乎分为两个部分:

  1. 在标签按下之前以及关闭之后进行监控
  2. 拦截选项卡按下并同步修改
  3. 在任何一种情况下,我们都必须知道 tab 键是导致菜单关闭的违规项目。

    如果我们使用标签来监听按键事件,则在开放输入中,如果没有搜索,它们将从.select2-selection发出;如果启用了搜索,则会select2-search__field

    $("body").on('keydown', e => { if (e.keyCode === 9) console.log(e.target) });
    

    Select 2 Tab Events

    然而,如果我们设置为委托处理程序,如上所述,当事件一直冒泡到“正文”时,菜单已经关闭,从而清除了目前突出显示的项目,甚至是我们是否开始公开的指标。

    我们可以在菜单关闭之前拦截,注册select2:closing这样的事件:

    $("body").on('select2:closing', e => { console.log(e,e.target) });
    

    但是,选择2不会保留原始事件信息,而是创建自己的新jQueryEvent,因此我们还不知道我们是否因为标签而关闭事件(body.keypress事件随后触发)

    解决方案

    我们将监控select2:closing事件并捕获我们需要知道的内容。接下来,我们需要附加一个处理程序,该处理程序在事件管道完成时侦听后续触发初始单击或键击。我们需要为每个关闭选项触发一次 。为此,我们可以使用此扩展程序$.fn.once。如果它是由选项卡引发的,它将更新在关闭期间检测到的任何值。如果没有,那个值和处理程序就会消失。

    总而言之,它应该是这样的:

    // monitor every time we're about to close a menu
    $("body").on('select2:closing', function (e) {
      // save in case we want it
      var $sel2 = $(e.target).data("select2");
      var $sel = $sel2.$element;
      var $selDropdown = $sel2.$results.find(".select2-results__option--highlighted")
      var newValue =  $selDropdown.data("data").element.value;
    
      // must be closed by a mouse or keyboard - listen when that event is finished
      // this must fire once and only once for every possible menu close 
      // otherwise the handler will be sitting around with unintended side affects
      $("html").once('keyup mouseup', function (e) {
    
        // if close was due to a tab, use the highlighted value
        var KEYS = { UP: 38, DOWN: 40, TAB: 9 }
        if (e.keyCode === KEYS.TAB) {
          if (newValue != undefined) {
            $sel.val(newValue);
            $sel.trigger('change');
          }
        }
    
      });
    
    });
    
    $.fn.once = function (events, callback) {
        return this.each(function () {
            $(this).on(events, myCallback);
            function myCallback(e) {
                $(this).off(events, myCallback);
                callback.call(this, e);
            }
        });
    };
    

    jsFiddle和StackSnippets中的工作演示:

    $('.select2').select2({});
    
    // monitor every time we're about to close a menu
    $("body").on('select2:closing', function (e) {
    	// save in case we want it
    	var $sel2 = $(e.target).data("select2");
      var $sel = $sel2.$element;
      var $selDropdown = $sel2.$results.find(".select2-results__option--highlighted")
      var newValue =  $selDropdown.data("data").element.value;
    
      // must be closed by a mouse or keyboard - setup listener to see when that event is completely done
      // this must fire once and only once for every possible menu close 
      // otherwise the handler will be sitting around with unintended side affects
      $("html").once('keyup mouseup', function (e) {
    
        // if close was due to a tab, use the highlighted value
        var KEYS = { UP: 38, DOWN: 40, TAB: 9 }
        if (e.keyCode === KEYS.TAB) {
          if (newValue != undefined) {
            $sel.val(newValue);
            $sel.trigger('change');
          }
        }
    
      });
      
    });
    
    $.fn.once = function (events, callback) {
        return this.each(function () {
            $(this).on(events, myCallback);
            function myCallback(e) {
                $(this).off(events, myCallback);
                callback.call(this, e);
            }
        });
    };
    .form-control {
      padding:10px;
      display:inline-block;
    }
    select {
      width: 100px;
      border: 1px solid #aaa;
      border-radius: 4px;
      height: 28px;
    }
    <link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/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.0/js/select2.js"></script>
    
    <div class="form-control">
      <label for="foods2">Select2</label>
      <select id="foods2" class="select2" >
        <option value="1">Apple</option>
        <option value="2">Banana</option>
        <option value="3">Carrot</option>
        <option value="4">Donut</option>
      </select>
    </div>