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

问题描述 投票:0回答:1

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

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

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

SelectOnClose violation of principle of least surprise

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

Here's an MCVE in jsFiddle and StackSnippets:

$('.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>
javascript jquery jquery-select2 jquery-select2-4
1个回答
1
投票

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

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

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

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

  1. 在标签按下之前以及关闭之后监控
  2. 拦截选项卡同步按下并修改

在任何一种情况下,我们都必须知道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) });

但是,select 2不会保留原始事件信息,而是自己创建新的jQueryEvent,所以我们还不知道我们是否因为tab事件而关闭(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);
        }
    });
};

Working demo in jsFiddle and 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>
© www.soinside.com 2019 - 2024. All rights reserved.