Я хотел бы узнать, в Javascript, какой элемент в данный момент сосредоточен. Я просматривал DOM и еще не нашел того, что мне нужно. Есть ли способ сделать это и как?
Я искал это:
Я пытаюсь сделать такие клавиши, как стрелки, и enter
перемещаться по таблице элементов ввода. Теперь вкладка работает, но ввод и стрелки по умолчанию не отображаются. У меня есть часть обработки ключей, но теперь мне нужно выяснить, как переместить фокус в функции обработки событий.
Используйте document.activeElement
, он поддерживается во всех основных браузерах.
Раньше, если вы пытались выяснить, в каком поле формы сосредоточено, вы не могли. Чтобы эмулировать обнаружение в старых браузерах, добавьте обработчик событий "focus" ко всем полям и запишите поле с последней фокусировкой в переменной. Добавьте обработчик "размытия", чтобы очистить переменную при событии размытия для поля с последней фокусировкой.
Ссылки по теме:
Как сказал JW, вы не можете найти текущий сфокусированный элемент, по крайней мере, независимо от браузера. Но если ваше приложение только IE (некоторые из них...), вы можете найти его следующим образом:
document.activeElement
EDIT: похоже, что у IE не было ничего плохого, это часть черновика HTML5 и, по-видимому, поддерживается последней версией Chrome, Safari и Firefox по крайней мере.
Если вы можете использовать jQuery, теперь он поддерживает: focus, просто убедитесь, что вы используете версию 1.6 +.
Этот оператор предоставит вам сосредоточенный в данный момент элемент.
$(":focus")
От: Как выбрать элемент, который сфокусирован на нем с помощью jQuery
return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
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
может по умолчанию использовать элемент <body>
, если в фокусе нет фокусируемых элементов. Кроме того, если элемент сфокусирован и окно браузера размыто, activeElement
продолжит удерживать сфокусированный элемент.
Если одно из этих двух вариантов поведения нежелательно, рассмотрите подход на основе CSS: document.querySelector( ':focus' )
.
querySelector
: stackoverflow.com/a/40873560/2624876
Мне понравился подход, используемый Джоэлем С., но мне также нравится простота 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);
$("*:focus")
?
Небольшой помощник, который я использовал для этих целей в 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 на странице html должен существовать <!DOCTYPE...
. Вот пример, предполагающий, что вы присвоили идентификатор элементу с фокусом:
$(":focus").each(function() {
alert($(this).attr("id") + " has focus!");
});
this.id
вместо $(this).attr('id')
или, по крайней мере (когда у вас уже есть объект jQuery) $(this)[0].id
. Родной Javascript на этом уровне намного быстрее и эффективнее. В этом случае может не быть заметным, но в масштабе всей системы вы заметите разницу.
Сам по себе document.activeElement
может возвращать элемент, если документ не сфокусирован. Возможно, вы захотите этого поведения, но если вы этого не сделаете, вы можете проверить document.hasFocus()
:
var focused_element =
document.hasFocus() &&
document.activeElement !== document.body &&
document.activeElement !== document.documentElement &&
document.activeElement;
Чтобы проверить, имеет ли конкретный элемент фокус:
var input_focused = document.activeElement === input && document.hasFocus();
В качестве альтернативы вы можете использовать события, но для этого требуется установка и предполагается исходное состояние:
var input_focused = false;
input.addEventListener("focus", function() {
input_focused = true;
});
input.addEventListener("blur", function() {
input_focused = false;
});
Если вы хотите получить объект, являющийся экземпляром Element
, вы должны использовать document.activeElement
, но если вы хотите получить объект, являющийся экземпляром Text
, вы должны использовать document.getSelection().focusNode
.
Я надеюсь, что это поможет.
document.getSelection().focusNode.parentElement
и нажмите «Ввод». После этого пропустите document.activeElement
и сделайте то же самое. ;)
Существуют потенциальные проблемы с использованием document.activeElement. Рассмотрим:
<div contentEditable="true">
<div>Some text</div>
<div>Some text</div>
<div>Some text</div>
</div>
Если пользователь фокусируется на внутреннем-div, тогда document.activeElement по-прежнему ссылается на внешний div. Вы не можете использовать document.activeElement, чтобы определить, какой из внутренних div имеет фокус.
Следующая функция обходит вокруг этого и возвращает сфокусированный node:
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
: внутренние элементы <div>
фактически не могут получить фокус, как вы можете видеть визуально, установив псевдокласс :focus
в что-то видимое (пример: jsfiddle.net/4gasa1t2/1 ) , То, о чем вы говорите, это то, что из внутренних <div>
содержит выделение или символ вставки, что является отдельной проблемой.
Если вы используете 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
});
}
С помощью dojo вы можете использовать dijit.getFocus()
Просто поставив это здесь, чтобы дать решение, которое я в итоге придумал.
Я создал свойство document.activeInputArea и использовал аддон jQuery HotKeys для блокировки событий клавиатуры для клавиш со стрелками, вкладки и ввода, и я создал обработчик событий для щелчка по входным элементам.
Затем я менял activeInputArea каждый раз, когда менялся фокус, поэтому я мог использовать это свойство, чтобы узнать, где я был.
Легко это испортить, потому что, если у вас есть ошибка в системе, и фокус не там, где вы думаете, то очень сложно восстановить правильный фокус.
Почти независимый от браузера способ достичь этого был сделан Quirksmode давным-давно. У него могут быть проблемы с Safari, поскольку Safari не всегда устанавливает события на тех же элементах, что и Chrome или Firefox. Иногда Safari даже устанавливает событие на текстовое поле вместо содержащего элемента. Это может быть исправлено после времени (путем проверки nodeType).
Вот он:
function getFocus(e){
var focused;
if (!e) var e = window.event;
if (e.target) focused = e.target;
else if (e.srcElement) focused = e.srcElement;
if (focused.nodeType == 3) focused = focused.parentNode;
if (document.querySelector) {
return focused.id;
} else if (!focused || focused == document.documentElement) {
return focused;
}
}
Надеюсь, что это поможет.
Благодаря Quirksmode
Google Chrome (по крайней мере, до 33) имеет раздражающую ошибку с document.activeElement
: в документах XHTML document.activeElement
есть undefined
. Я не тестировал другие браузеры на основе webkit, они также могут быть затронуты.
Я нашел следующий фрагмент, который будет полезен при попытке определить, какой элемент в данный момент имеет фокус. Скопируйте следующее в консоль своего браузера, и каждую секунду он распечатает детали текущего элемента с фокусом.
setInterval(function() { console.log(document.querySelector(":focus")); }, 1000);
Не стесняйтесь изменять console.log
, чтобы вывести что-то другое, чтобы помочь вам точно определить точный элемент, если распечатка всего элемента не поможет вам определить элемент.