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

977

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

Я искал это:

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

Теги:
dom

18 ответов

1029
Лучший ответ

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

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

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

  • 1
    Если ни один элемент не был сфокусирован, что возвращает document.activeElement? Можем ли мы рассчитывать на то, что он будет согласован между теми браузерами, которые его поддерживают?
  • 45
    Не уверен насчет IE, но FF и Safari оба возвращают элемент BODY.
Показать ещё 9 комментариев
95

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

document.activeElement

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

  • 5
    FF3 тоже. На самом деле это часть спецификации HTML5 вокруг «управления фокусом».
  • 2
    Работает в текущей версии Chrome и Opera (9.62). Не работает в Safari 3.2.3 на OS X, но работает в Safari 4, выпущенном вчера :)
Показать ещё 5 комментариев
76

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

Этот оператор предоставит вам сосредоточенный в данный момент элемент.

$(":focus")

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

  • 1
    Это хорошо, но как это делает jQuery? document.activeElement? Я нашел это: return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
37

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.

11

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

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

  • 0
    Круто, да, в моем случае ваш подход имел абсолютный смысл. Я могу установить свои фокусируемые элементы с помощью 'tabindex = "- 1" ", если ни один из них не имеет фокуса (скажем, некоторого текста или рисунка, который меня не волнует), то document.querySelector (': focus ') возвращает ноль.
  • 0
    Смотрите мой ответ, чтобы избежать использования querySelector : stackoverflow.com/a/40873560/2624876
10

Мне понравился подход, используемый Джоэлем С., но мне также нравится простота 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);
  • 3
    Может ли это быть заменено @William Denniss's $("*:focus") ?
  • 0
    Я полагаю, что это возможно. Я написал это давным-давно, и у меня никогда не было оснований пересматривать лучшее решение сейчас, когда оно прошло 5 лет. Попробуйте! Я мог бы просто сделать то же самое. Я меньше плагин на нашем сайте! :)
9

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

7

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

$(":focus").each(function() {
  alert($(this).attr("id") + " has focus!");
});
  • 0
    Вы должны (всегда?) Использовать this.id вместо $(this).attr('id') или, по крайней мере (когда у вас уже есть объект jQuery) $(this)[0].id . Родной Javascript на этом уровне намного быстрее и эффективнее. В этом случае может не быть заметным, но в масштабе всей системы вы заметите разницу.
5

Сам по себе 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;
});
5

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

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

  • 0
    Лучше чем?
  • 0
    Откройте инспектор вашего браузера, щелкните в любом месте страницы, перейдите мимо этого document.getSelection().focusNode.parentElement и нажмите «Ввод». После этого пропустите document.activeElement и сделайте то же самое. ;)
Показать ещё 9 комментариев
5

Существуют потенциальные проблемы с использованием 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;
  }
}
  • 3
    На самом деле это не проблема для document.activeElement : внутренние элементы <div> фактически не могут получить фокус, как вы можете видеть визуально, установив псевдокласс :focus в что-то видимое (пример: jsfiddle.net/4gasa1t2/1 ) , То, о чем вы говорите, это то, что из внутренних <div> содержит выделение или символ вставки, что является отдельной проблемой.
5

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

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

Прочитав другие ответы и попробовав себя, кажется, что 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
  });
}
4

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

3

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

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

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

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

2

Почти независимый от браузера способ достичь этого был сделан 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

1

Google Chrome (по крайней мере, до 33) имеет раздражающую ошибку с document.activeElement: в документах XHTML document.activeElement есть undefined. Я не тестировал другие браузеры на основе webkit, они также могут быть затронуты.

0

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

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню