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

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

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

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

22 ответа

Решение

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

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

Ссылки по теме:

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

document.activeElement

РЕДАКТИРОВАТЬ: Похоже, что IE не все не так, в конце концов, это часть проекта HTML5 и, кажется, поддерживается по крайней мере последней версии Chrome, Safari и Firefox.

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

Это утверждение даст вам в настоящее время сосредоточенный элемент.

$(":focus")

От: Как выбрать элемент, который фокусируется на нем, с помощью 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 когда ничего не сфокусировано.

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


Вот ("тяжелые воздушные кавычки") "однострочная" версия получения сфокусированного элемента, которая концептуально более сложна, потому что вы должны знать о коротком замыкании, и, знаете, очевидно, что она не помещается на одной строке, предполагая, что вы хочу, чтобы это было читабельно.
Я не буду рекомендовать это. Но если вы 1337 hax0r, idk... это там.
Вы также можете удалить || null расстаться, если вы не против получить false в некоторых случаях. (Вы все еще можете получить null если document.activeElement является 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' ),

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

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

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

Маленький помощник, который я использовал для этих целей в 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() был вызван для данного элемента.

Мне понравился подход, использованный Джоэлем С, но я также люблю простоту 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);

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

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

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

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

Есть потенциальные проблемы с использованием document.activeElement. Рассматривать:

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

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

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

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;
  }
}

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

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

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

Если у вас есть браузер, который не поддерживает document.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
  });
}

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

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

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

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

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

использоватьdocument.activeElement.id

добавление.idотфильтровывает возврат всего DOM и позволяет работать только с идентифицированными элементами

просто используйте document.activeElement, чтобы найти текущий активный элемент

Я думаю, что ответ Кристиана наиболее близок к правильному; с добавлением того, чтоfocusoutсобытие имеет свойство с именемrelatedTargetэто позволяет выяснить, что получило фокус.

      document.addEventListener("focusout",ev => {
  const focusedElement = ev.relatedTarget;

  // ...
});

Другие ответы, которые используютquerySelector(':focus')иactiveElementесть досадные оговорки.

https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent/relatedTarget

Вы можете использовать свойство document.activeElement, чтобы определить, какой элемент DOM в данный момент находится в фокусе. Это свойство вернет текущий элемент документа в фокусе или значение null, если ни один элемент не имеет фокуса. Вы можете использовать это свойство в сочетании с прослушивателем событий, чтобы обнаружить изменение фокуса. например:

      document.addEventListener('focusin', function(event) {
  console.log('Focused element:', document.activeElement);
});

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

      $(":focus")

Какdocument.activeElementизменится наbodyкогда вы нажимаете что-либо в инструменте разработчика.

Чтобы получить предыдущий активный элемент, добавьте это.

Пример: вы нажимаете на кнопку и вам нужен предыдущий активный элемент. Поскольку кнопка получает фокус после нажатия на нее.

      document.addEventListener("focusout",ev => {
  document.previousActiveElement = ev.target;
});
Другие вопросы по тегам