Как узнать, какой элемент DOM имеет фокус?

Я хотел бы узнать, в JavaScript, какой элемент в данный момент имеет фокус. Я просмотрел дом и пока не нашел то, что мне нужно. Есть ли способ сделать это, и как?

причина, по которой я искал вот это:

Я пытаюсь сделать ключи как стрелы и enter перейдите по таблице входных элементов. Вкладка работает сейчас, но enter, и стрелки по умолчанию не кажется. У меня есть ключ управления, но теперь мне нужно выяснить, как переместите фокус в функции обработки событий.

16 ответов


использовать document.activeElement, он поддерживается во всех основных браузерах.

ранее, если вы пытались выяснить, какое поле формы имеет фокус, вы не могли. Чтобы эмулировать обнаружение в старых браузерах, добавьте обработчик событий "фокус" ко всем полям и запишите последнее поле в переменную. Добавьте обработчик "размытия", чтобы очистить переменную при событии размытия для последнего сфокусированного поля.

ссылки:


Как сказал JW, вы не можете найти текущий сфокусированный элемент, по крайней мере, независимым от браузера способом. Но если ваше приложение только IE (некоторые из них...), вы можете найти его следующим образом :

document.activeElement

EDIT: похоже, что IE не все неправильно, в конце концов, это часть проекта HTML5 и, похоже, поддерживается последней версией Chrome, Safari и Firefox, по крайней мере.


Если вы можете использовать jQuery, теперь он поддерживает :фокус, просто убедитесь, что вы используете версию 1.6+.

этот оператор даст вам текущий сфокусированный элемент.

$(":focus")

From:Как выбрать элемент, который имеет фокус на нем с помощью jQuery


document.activeElement теперь часть рабочего проекта HTML5 спецификация, но она может еще не поддерживаться в некоторых не основных/мобильных / старых браузерах. Вы можете вернуться к querySelector (если это поддерживается). Также стоит упомянуть, что document.activeElement вернутся document.body если элемент не сфокусирован-даже если окно браузера не имеет фокуса.

следующий код будет работать вокруг этой проблемы и вернуться к querySelector давая немного лучше поддержка.

var focused = document.activeElement;
if (!focused || focused == document.body)
    focused = null;
else if (document.querySelector)
    focused = document.querySelector(":focus");

следует отметить, что разница в производительности между этими двумя методами. Запрос документа с селекторами всегда будет намного медленнее, чем доступ к activeElement собственность. Смотрите этоjsperf.com тест.


сама по себе document.activeElement все еще может вернуть элемент, если документ не сфокусирован (и, таким образом,ничего в документе ориентирован!)

вы мая хотите такое поведение, или это мая не имеет значения (например, в пределах keydown событие), но если вам нужно знать, что что-то действительно сосредоточено, вы можете дополнительно проверить document.hasFocus().

следующее даст вам сфокусированный элемент, если он есть, или null.

var focused_element = null;
if (
    document.hasFocus() &&
    document.activeElement !== document.body &&
    document.activeElement !== document.documentElement
) {
    focused_element = document.activeElement;
}

чтобы проверить, является ли конкретные элемент имеет фокус, оно проще:

var input_focused = document.activeElement === input && document.hasFocus();

чтобы проверить, является ли что-нибудь сфокусировано, оно более сложное снова:

var anything_is_focused = (
    document.hasFocus() &&
    document.activeElement !== null &&
    document.activeElement !== document.body &&
    document.activeElement !== document.documentElement
);

Надежность Примечание: в коде, где он проверяет против document.body и document.documentElement, это потому, что некоторые браузеры возвращают один из этих или null когда ничто не сфокусировано.

это не учитывает, если the <body> (или <html>) было tabIndex атрибут, и таким образом на самом деле может быть сосредоточен. Если вы пишете библиотеку или что-то еще и хотите, чтобы она была надежной, вы, вероятно, должны как-то справиться с этим.


здесь (тяжелый airquotes)" однострочный " вариант получения сфокусированного элемента, который является концептуально сложнее потому что вы должны знать о коротком замыкании, и вы знаете, это, очевидно, не подходит на одном строка, предполагая, что вы хотите, чтобы она была читаемой.
Я не буду рекомендовать это. Но если вы 1337 hax0r, idk... он там.
Вы также можете удалить || null если вы не против false в некоторых случаях. (Вы все еще можете получить null если document.activeElement is null):

var focused_element = (
    document.hasFocus() &&
    document.activeElement !== document.body &&
    document.activeElement !== document.documentElement &&
    document.activeElement
) || null;

для проверки, если элемент находится в фокусе, в качестве альтернативы вы мог бы использовать события, но этот способ требует настройки (и потенциально демонтажа), и главное, предполагает начальное состояние:

var input_focused = false;
input.addEventListener("focus", function() {
    input_focused = true;
});
input.addEventListener("blur", function() {
    input_focused = false;
});

можно зафиксировать исходное состояние предположения с помощью не событийными, но тогда вы могли бы также просто использовать это вместо этого.


document.activeElement по умолчанию может быть <body> элемент, если в фокусе нет фокусируемых элементов. Кроме того, если элемент сфокусирован и окно браузера размыто,activeElement будет продолжать удерживать сфокусированный элемент.

если любое из этих двух действий нежелательно, рассмотрите подход на основе CSS:document.querySelector( ':focus' ).


мне понравился подход, используемый Джоэлом S, но я также люблю простоту document.activeElement. Я использовал jQuery и объединил их. Старые браузеры, которые не поддерживают document.activeElement использовать jQuery.data() для хранения значения "hasFocus". Новые браузеры будут использовать document.activeElement. Я предполагаю, что document.activeElement будет иметь более высокую производительность.

(function($) {
var settings;
$.fn.focusTracker = function(options) {
    settings = $.extend({}, $.focusTracker.defaults, options);

    if (!document.activeElement) {
        this.each(function() {
            var $this = $(this).data('hasFocus', false);

            $this.focus(function(event) {
                $this.data('hasFocus', true);
            });
            $this.blur(function(event) {
                $this.data('hasFocus', false);
            });
        });
    }
    return this;
};

$.fn.hasFocus = function() {
    if (this.length === 0) { return false; }
    if (document.activeElement) {
        return this.get(0) === document.activeElement;
    }
    return this.data('hasFocus');
};

$.focusTracker = {
    defaults: {
        context: 'body'
    },
    focusedElement: function(context) {
        var focused;
        if (!context) { context = settings.context; }
        if (document.activeElement) {
            if ($(document.activeElement).closest(context).length > 0) {
                focused = document.activeElement;
            }
        } else {
            $(':visible:enabled', context).each(function() {
                if ($(this).data('hasFocus')) {
                    focused = this;
                    return false;
                }
            });
        }
        return $(focused);
    }
};
})(jQuery);

маленький помощник, который я использовал для этих целей в Mootools:

FocusTracker = {
    startFocusTracking: function() {
       this.store('hasFocus', false);
       this.addEvent('focus', function() { this.store('hasFocus', true); });
       this.addEvent('blur', function() { this.store('hasFocus', false); });
    },

    hasFocus: function() {
       return this.retrieve('hasFocus');
    }
}

Element.implement(FocusTracker);

таким образом, вы можете проверить, имеет ли элемент фокус с el.hasFocus() предусмотрено, что startFocusTracking() вызывается для данного элемента.


JQuery поддерживает :focus псевдо-класс по состоянию на текущий момент. Если вы ищете его в документации JQuery, проверьте в разделе "селекторы", где он указывает на W3C CSS docs. Я тестировал с Chrome, FF и IE 7+. Обратите внимание, что для его работы в IE,<!DOCTYPE... должен существовать на странице html. Вот пример, предполагающий, что вы назначили идентификатор элементу, который имеет фокус:

$(":focus").each(function() {
  alert($(this).attr("id") + " has focus!");
});

если вы хотите получить объект, который является экземпляром Element, вы должны использовать document.activeElement, а если вы хотите получить объект, который является экземпляром Text, вы должны использовать document.getSelection().focusNode.

надеюсь, поможет.


есть потенциальные проблемы с использованием документа.activeElement. Подумайте:

<div contentEditable="true">
  <div>Some text</div>
  <div>Some text</div>
  <div>Some text</div>
</div>

если пользователь фокусируется на внутреннем div, то документ.activeElement по-прежнему ссылается на внешний div. Нельзя использовать документ.activeElement, чтобы определить, какой из внутренних div имеет фокус.

следующая функция обходит это и возвращает сфокусированный узел:

function active_node(){
  return window.getSelection().anchorNode;
}

Если вы хотите получить сфокусированный элемент, используйте:

function active_element(){
  var anchor = window.getSelection().anchorNode;
  if(anchor.nodeType == 3){
        return anchor.parentNode;
  }else if(anchor.nodeType == 1){
        return anchor;
  }
}

чтение других ответов и попытка себя, кажется document.activeElement даст вам элемент в большинстве браузеров.

Если у вас есть браузер, который не поддерживает документ.activeElement если у вас есть jQuery, вы должны иметь возможность заполнить его на всех событиях фокуса чем-то очень простым (непроверенным, поскольку у меня нет браузера, отвечающего этим критериям):

if (typeof document.activeElement === 'undefined') { // Check browser doesn't do it anyway
  $('*').live('focus', function () { // Attach to all focus events using .live()
    document.activeElement = this; // Set activeElement to the element that has been focussed
  });
}

Если вы используете jQuery, вы можете использовать это, чтобы узнать, активен ли элемент:

$("input#id").is(":active");

с dojo вы можете использовать dijit.getFocus()


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

Я создал свойство под названием document.activeInputArea, и использовал горячие клавиши jQuery для ловушки событий клавиатуры для клавиш со стрелками, tab и enter, и я создал обработчик событий для нажатия на элементы ввода.

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

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


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

setInterval(function() { console.log(document.querySelector(":focus")); }, 1000);

Не стесняйтесь изменять console.log чтобы выйти из системы что-то другое, чтобы помочь вам точно определить элемент, если печать всего элемента не поможет вам точно определить элемент.