13

我目前无法<select>在 Firefox (38.0.5) 中选择启用 Select2 的元素 - 换句话说,无法以<option>无鼠标方式访问选择。在 Chrome 中,您可以在表单中按 Tab 并按下enter以开始选择 Select2select元素中的项目。我没有在其他浏览器中测试过,但在提交实际的错误报告之前,我想验证其他人是否遇到同样的问题?

您可以在演示页面上复制

  • 选择2 v4.0.0
  • Twitter Bootstrap 3.3.4(虽然没有为 Bootstrap 添加任何额外的样式)
  • 火狐 v38.0.5
4

4 回答 4

13

虽然它不是一个完美的解决方案,但以下是我们用来在包含 Select2 元素的 HTML 表单上模拟普通键盘导航的方法。

/**
 * WARNING: untested using Select2's option ['selectOnClose'=>true]
 *
 * This code was written because the Select2 widget does not handle
 * tabbing from one form field to another.  The desired behavior is that
 * the user can use [Enter] to select a value from Select2 and [Tab] to move
 * to the next field on the form.
 *
 * The following code moves focus to the next form field when a Select2 'close'
 * event is triggered.  If the next form field is a Select2 widget, the widget
 * is opened automatically.
 *
 * Users that click elsewhere on the document will cause the active Select2
 * widget to close.  To prevent the code from overriding the user's focus choice
 * a flag is added to each element that the users clicks on.  If the flag is
 * active, then the automatic focus script does not happen.
 *
 * To prevent conflicts with multiple Select2 widgets opening at once, a second
 * flag is used to indicate the open status of a Select2 widget.  It was
 * necessary to use a flag instead of reading the class '--open' because using the
 * class '--open' as an indicator flag caused timing/bubbling issues.
 *
 * To simulate a Shift+Tab event, a flag is recorded every time the shift key
 * is pressed.
 */
jQuery(document).ready(function($) {
    var docBody = $(document.body);
    var shiftPressed = false;
    var clickedOutside = false;
    //var keyPressed = 0;

    docBody.on('keydown', function(e) {
        var keyCaptured = (e.keyCode ? e.keyCode : e.which);
        //shiftPressed = keyCaptured == 16 ? true : false;
        if (keyCaptured == 16) { shiftPressed = true; }
    });
    docBody.on('keyup', function(e) {
        var keyCaptured = (e.keyCode ? e.keyCode : e.which);
        //shiftPressed = keyCaptured == 16 ? true : false;
        if (keyCaptured == 16) { shiftPressed = false; }
    });

    docBody.on('mousedown', function(e){
        // remove other focused references
        clickedOutside = false;
        // record focus
        if ($(e.target).is('[class*="select2"]')!=true) {
            clickedOutside = true;
        }
    });

    docBody.on('select2:opening', function(e) {
        // this element has focus, remove other flags
        clickedOutside = false;
        // flag this Select2 as open
        $(e.target).attr('data-s2open', 1);
    });
    docBody.on('select2:closing', function(e) {
        // remove flag as Select2 is now closed
        $(e.target).removeAttr('data-s2open');
    });

    docBody.on('select2:close', function(e) {
        var elSelect = $(e.target);
        elSelect.removeAttr('data-s2open');
        var currentForm = elSelect.closest('form');
        var othersOpen = currentForm.has('[data-s2open]').length;
        if (othersOpen == 0 && clickedOutside==false) {
            /* Find all inputs on the current form that would normally not be focus`able:
             *  - includes hidden <select> elements whose parents are visible (Select2)
             *  - EXCLUDES hidden <input>, hidden <button>, and hidden <textarea> elements
             *  - EXCLUDES disabled inputs
             *  - EXCLUDES read-only inputs
             */
            var inputs = currentForm.find(':input:enabled:not([readonly], input:hidden, button:hidden, textarea:hidden)')
                .not(function () {   // do not include inputs with hidden parents
                    return $(this).parent().is(':hidden');
                });
            var elFocus = null;
            $.each(inputs, function (index) {
                var elInput = $(this);
                if (elInput.attr('id') == elSelect.attr('id')) {
                    if ( shiftPressed) { // Shift+Tab
                        elFocus = inputs.eq(index - 1);
                    } else {
                        elFocus = inputs.eq(index + 1);
                    }
                    return false;
                }
            });
            if (elFocus !== null) {
                // automatically move focus to the next field on the form
                var isSelect2 = elFocus.siblings('.select2').length > 0;
                if (isSelect2) {
                    elFocus.select2('open');
                } else {
                    elFocus.focus();
                }
            }
        }
    });

    /**
     * Capture event where the user entered a Select2 control using the keyboard.
     * http://stackoverflow.com/questions/20989458
     * http://stackoverflow.com/questions/1318076
     */
    docBody.on('focus', '.select2', function(e) {
        var elSelect = $(this).siblings('select');
        if (elSelect.is('[disabled]')==false && elSelect.is('[data-s2open]')==false
            && $(this).has('.select2-selection--single').length>0) {
            elSelect.attr('data-s2open', 1);
            elSelect.select2('open');
        }
    });

});
于 2016-09-21T00:47:27.123 回答
7

基于 zDaniels 出色的答案。

我已经创建了代码的凉亭可安装版本。

$ bower install select2-tab-fix

来源和文档位于

https://github.com/peledies/select2-tab-fix

于 2017-03-15T19:52:45.487 回答
5

这也让我很困扰,所以我把它设置为焦点打开。So when tabbing to the select, it will open automatically.

$(document).ready(function () {
    $(".select2-selection").on("focus", function () {
        $(this).parent().parent().prev().select2("open");
    });
});

希望对您有所帮助,我使用的是不同版本的 Bootstrap 和 firefox,所以如果没有,请告诉我!

于 2016-01-29T23:13:14.413 回答
0

使用@zDaniels 答案,它就像一个魅力。但唯一的问题是它不会关闭最后一个select2。要解决此问题,您可以在最后一个 select2 元素的 on-change 事件中编写一个带有以下行的 jquery 函数。我希望这有助于进行调整。

    $(document).ready(function () {
      $(YOUR_LAST_ELEMENT).on("change", function () {
        $(this).parent().parent().prev().select2("close");
      });
    });
于 2020-03-17T00:37:44.170 回答