Как узнать, какой элемент 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 при каждом изменении фокуса, чтобы я мог использовать это свойство, чтобы узнать, где я был.
Хотя это легко испортить, потому что, если у вас есть ошибка в системе, а фокус не там, где вы думаете, то восстановить правильную фокусировку очень сложно.
использовать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;
});