Есть ли селектор jQuery для получения всех элементов, которые могут получить фокус?

Этот ответ указывает, какие элементы HTML могут получать фокус. Есть ли селектор jQuery, который соответствует именно этим элементам?

Пока я просто использую $('input,select,textarea,a'), но мне интересно, есть ли что-то более точное.

Ответ 1

Из другого ответа SO, на который ссылается OP:

Сегодня браузеры определяют focus() на HTMLElement,...

Итак, это означает, что тестирование для focus в качестве элемента элемента неэффективно, потому что все элементы будут иметь его, независимо от того, принимают ли они фактически фокус или нет.

... но элемент на самом деле не будет фокусироваться, если только один из них:

  • HTMLAnchorElement/HTMLAreaElement с href * HTMLInputElement/HTMLSelectElement/HTMLTextAreaElement/HTMLButtonElement но не с disabled (IE действительно дает вам ошибку, если вы пытаетесь), и загрузки файлов имеют необычное поведение по соображениям безопасности.
  • HTMLIFrameElement (хотя фокусировка на него не делает ничего полезного). Другие элементы внедрения также, может быть, я их не тестировал.
  • Любой элемент с tabindex

Итак, как насчет того, чтобы явно обозначить все это в jQuery Selector?

$('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]')

Обновление # 1:

I обновил jsFiddle здесь. Кажется, что он работает.

Я также добавил элементы с атрибутом contenteditable в список выше.


Обновление # 2:

Как заметил @jfriend00: "В зависимости от использования, вы можете отфильтровать элементы, которые не видны". Чтобы выполнить это, просто примените . Filter (': visible') к набору, сгенерированному из указанного выше селектора.


Обновление # 3:

Как Xavin указал: jQuery UI теперь имеет селектор, : focusable, который выполняет эту функцию. Если вы уже используете jQuery UI, это может быть путь. Если нет, то вы можете захотеть проверить, как работает jQuery UI. В любом случае полезно использовать описание на странице пользовательского интерфейса jQuery для :focusable:

Элементы следующего типа могут быть сфокусированы, если они не отключены: ввод, выбор, текстовое поле, кнопка и объект. Якорями можно сфокусировать, если они имеют атрибут href или tabindex. элементы области могут быть сфокусированы, если они находятся внутри именованной карты, имеют атрибут href, и на карте отображается видимое изображение. Все остальные элементы настраиваются только на основе атрибута tabindex и видимости.

Итак, селектор, который я предложил выше, близок, но он не учитывает несколько нюансов.

Здесь функция ripped из jQuery UI, с небольшими изменениями, чтобы сделать ее автономной. (адаптация не проверена, но должна работать):

function focusable( element ) {
    var map, mapName, img,
        nodeName = element.nodeName.toLowerCase(),
        isTabIndexNotNaN = !isNaN( $.attr( element, "tabindex" ) );
    if ( "area" === nodeName ) {
        map = element.parentNode;
        mapName = map.name;
        if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
            return false;
        }
        img = $( "img[usemap=#" + mapName + "]" )[0];
        return !!img && visible( img );
    }
    return ( /input|select|textarea|button|object/.test( nodeName ) ?
        !element.disabled :
        "a" === nodeName ?
            element.href || isTabIndexNotNaN :
            isTabIndexNotNaN) &&
        // the element and all of its ancestors must be visible
        visible( element );

    function visible( element ) {
      return $.expr.filters.visible( element ) &&
        !$( element ).parents().addBack().filter(function() {
          return $.css( this, "visibility" ) === "hidden";
        }).length;
    }
}

Примечание: вышеуказанная функция все еще зависит от jQuery, но не требует пользовательского интерфейса jQuery.

Ответ 2

Вы можете проверить элементы, которые имеют функцию focus():

$('*').each(function() {
  if(typeof this.focus == 'function') {
    // Do something with this element
  }
}) ;

Изменить Думая немного больше, вероятно, имеет смысл иметь *:visible, а не просто * как селектор для большинства приложений этого.

Ответ 3

Другой простой, но полный, селектор jQuery может быть следующим:

$('a[href], area[href], input, select, textarea, button, iframe, object, embed, *[tabindex], *[contenteditable]')
.not('[tabindex=-1], [disabled], :hidden')

Ответ 4

У меня есть относительно простое решение, которое возвращает все дочерние элементы tabbable в порядке их вкладок без использования jQuery.

function tabbable(el) {
    return [].map.call(el.querySelectorAll([
        'input',
        'select',
        'a[href]',
        'textarea',
        'button',
        '[tabindex]'
    ]), function(el, i) { return { el, i } }).
        filter(function(e) {
            return e.el.tabIndex >= 0 && !e.el.disabled && e.el.offsetParent; }).
        sort(function(a,b) {
            return a.el.tabIndex === b.el.tabIndex ? a.i - b.i : (a.el.tabIndex || 9E9) - (b.el.tabIndex || 9E9); });
}

Для IE рассмотрите возможность выполнения другой проверки видимости, чем e.el.offsetParent. jQuery может помочь вам здесь.

Если вам не нужны отсортированные элементы, оставьте вызов sort().

Ответ 5

В jQuery не существует селектор, который вы находите.

Если вы уже используете jQueryUI, вы можете использовать : focusable селектор.

http://api.jqueryui.com/focusable-selector/

Ответ 6

Общий тест, чтобы узнать, поддерживает ли элемент определенный тип слушателя, есть ли у него связанное свойство, например. для проверки поддержки фокусного события используйте:

if ('focus' in element) {
  // element supports the focus event
}

Однако есть некоторые исключения. См. Ответы на Как вы программно определяете, к какому событию может прослушиваться объект HTML?.

Ответ 7

Вместо того, чтобы получать список фокусируемых элементов, вы можете попробовать настроить обработчик фокуса в элементе body, который фиксирует фокусные события.

$(document.body).on("focus", "*", function(e) {
    //Scroll to e.target
});

Ответ 8

var allElementsThatCanBeFocused = $(':focusable');