Wie finde ich heraus, welches DOM-Element den Fokus hat?

1309

Ich möchte in JavaScript herausfinden, welches Element derzeit im Fokus steht. Ich habe das DOM durchgesehen und noch nicht gefunden, was ich brauche. Gibt es eine Möglichkeit, dies zu tun, und wie?

Der Grund, warum ich danach gesucht habe:

Ich versuche, Schlüssel wie die Pfeile zu erstellen und enterdurch eine Tabelle mit Eingabeelementen zu navigieren. Tab funktioniert jetzt, aber geben Sie ein, und Pfeile scheinen nicht standardmäßig zu sein. Ich habe den Schlüsselbehandlungsteil eingerichtet, aber jetzt muss ich herausfinden, wie der Fokus in den Ereignisbehandlungsfunktionen verschoben werden kann.

Tony Peterson
quelle
2
Hier ist ein Lesezeichen, das console.log das Element mit Fokus: github.com/lingtalfi/where-is-focus-bookmarklet
ling
Sie können das find-focused-elementPaket verwenden: npmjs.com/package/find-focused-element
Maxim Zhukov

Antworten:

1533

Verwendung document.activeElement, es wird in allen gängigen Browsern unterstützt.

Wenn Sie zuvor herausfinden wollten, welches Formularfeld den Fokus hat, konnten Sie dies nicht. Um die Erkennung in älteren Browsern zu emulieren, fügen Sie allen Feldern einen "Fokus" -Ereignishandler hinzu und zeichnen Sie das zuletzt fokussierte Feld in einer Variablen auf. Fügen Sie einen "Unschärfe" -Handler hinzu, um die Variable bei einem Unschärfeereignis für das zuletzt fokussierte Feld zu löschen.

Wenn Sie das entfernen müssen, activeElementkönnen Sie Unschärfe verwenden. document.activeElement.blur(). Es wird die Änderung activeElementzu body.

Verwandte Links:

Dave Jarvis
quelle
53
Ich bin mir über IE nicht sicher, aber FF und Safari geben beide das BODY-Element zurück.
JW.
10
activeElementgibt das fokussierte Element tatsächlich nicht zurück. Jedes Element kann fokussiert sein. Wenn ein Dokument 4 'scrolldivs' hat, kann 0 oder 1 dieser divs mit den Pfeiltasten gescrollt werden. Wenn Sie auf eine klicken, wird diese Div fokussiert. Wenn Sie außerhalb von allen klicken, ist der Körper fokussiert. Wie finden Sie heraus, welches scrolldiv fokussiert ist? jsfiddle.net/rudiedirkx/bC5ke/show (Konsole überprüfen)
Rudie
18
@Rudie, @Stewart: Ich habe auf Ihrer Geige aufgebaut, um einen ausgefeilteren Spielplatz zu schaffen: jsfiddle.net/mklement/72rTF . Sie werden feststellen, dass der einzige große Browser (Stand Ende 2012), der einen solchen Browser tatsächlich fokussieren kann, divFirefox 17 ist, und zwar nur durch Tippen darauf. Die Arten von Elementen , die alle gängigen Browser über das Rück document.activeElementsind beschränkt auf Eingabeelemente -bezogene. Wenn kein solches Element den Fokus hat, geben alle gängigen Browser das bodyElement zurück - mit Ausnahme von IE 9, das das htmlElement zurückgibt .
mklement0
10
Ich bin mir nicht sicher, ob es hilft, aber Sie können ein Element wie ein div dazu bringen, den Tastaturfokus zu erhalten, indem Sie das Attribut tabindex = "0"
Marco Luglio
4
Jeder Zugriff auf document.activeElementsollte in eine try catchDatei eingeschlossen werden, da dies unter bestimmten Umständen eine Ausnahme auslösen kann (nicht nur IE9 AFAIK). Siehe bugs.jquery.com/ticket/13393 und bugs.jqueryui.com/ticket/8443
Robocat
127

Wie von JW gesagt, können Sie das aktuell fokussierte Element zumindest browserunabhängig nicht finden. Wenn Ihre App jedoch nur IE ist (einige sind ...), können Sie sie folgendermaßen finden:

document.activeElement

BEARBEITEN: Es sieht so aus, als ob der IE doch nicht alles falsch gemacht hat. Dies ist Teil des HTML5-Entwurfs und scheint zumindest von der neuesten Version von Chrome, Safari und Firefox unterstützt zu werden.

Wookai
quelle
5
FF3 auch. Dies ist tatsächlich Teil der HTML5-Spezifikation zum Thema "Fokusverwaltung".
Crescent Fresh
2
Es funktioniert in der aktuellen Version von Chrome und Opera (9.62). Funktioniert nicht in Safari 3.2.3 unter OS X, aber es funktioniert in Safari 4, das gestern veröffentlicht wurde :)
Gregers
immer noch das gleiche für Chrom 19: S
Sebas
1
Es funktioniert nur in Chrome (20) / Safari (5.1.3), wenn Sie mit der Tastatur auf das Element tippen. Wenn Sie darauf klicken, können weder der Selektor jquery: focus noch das Dokument document.activeElement das zurückgeben, worauf Sie geklickt haben (undefiniertes Element bzw. Dokumentkörperelement zurückgeben). PS Ich kann nicht glauben, dass dieser Thread 2 Jahre alt ist und es immer noch Regressionsprobleme im Webkit gibt, zusammen mit dem, bei dem das Überspringen von Links nicht funktioniert, aber mit dem Hinzufügen von experimentellem CSS3 wird so viel Arbeit geleistet. Ich denke, ich kann meiner Familie und meinen Freunden wieder Firefox empfehlen.
Dawn
^^ document.activeElement ist in Ordnung, wenn Sie klicken, um sich auf einen Textbereich oder eine andere Eingabe zu konzentrieren. Wenn es sich um einen Link handelt, wird er beim Klicken nicht fokussiert (auf der Seite oder offensichtlich auf andere Weise).
Marksyzm
84

Wenn Sie jQuery verwenden können, unterstützt es jetzt: focus, stellen Sie einfach sicher, dass Sie Version 1.6+ verwenden.

Mit dieser Anweisung erhalten Sie das aktuell fokussierte Element.

$(":focus")

Von: So wählen Sie mit jQuery ein Element aus, auf das der Fokus liegt

William Denniss
quelle
4
Das ist gut, aber wie macht jQuery das? document.activeElement? Ich fand dies: return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
Harry Pehkonen
46

document.activeElementist jetzt Teil der HTML5-Entwurfsspezifikation , wird jedoch in einigen nicht wichtigen / mobilen / älteren Browsern möglicherweise noch nicht unterstützt. Sie können auf zurückgreifen querySelector(wenn dies unterstützt wird). Erwähnenswert ist auch, dass dies zurückgegeben document.activeElementwird, document.bodywenn kein Element fokussiert ist - auch wenn das Browserfenster keinen Fokus hat.

Der folgende Code umgeht dieses Problem und querySelectorbietet eine etwas bessere Unterstützung.

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

Zu beachten ist außerdem der Leistungsunterschied zwischen diesen beiden Methoden. Das Abfragen des Dokuments mit Selektoren ist immer viel langsamer als der Zugriff auf die activeElementEigenschaft. Siehe diesen jsperf.com-Test .

Andy E.
quelle
21

An sich document.activeElementkann immer noch ein Element zurück , wenn das Dokument nicht fokussiert ist (und damit nichts mehr im Dokument konzentriert sich!)

Sie können dieses Verhalten wollen, oder es kann nicht Sache (zB innerhalb eines keydownEreignisses), aber wenn Sie etwas wissen müssen , ist tatsächlich konzentriert, können Sie zusätzlich prüfen document.hasFocus().

Das Folgende gibt Ihnen das fokussierte Element, falls es eines gibt, oder sonst null.

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

Um zu überprüfen, ob ein bestimmtes Element den Fokus hat, ist es einfacher:

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

Um zu überprüfen, ob etwas fokussiert ist, ist es wieder komplexer:

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

Hinweis zur Robustheit : In dem Code, in dem gegen document.bodyund geprüft wird document.documentElement, liegt dies daran, dass einige Browser einen dieser Codes zurückgeben oder nullwenn nichts fokussiert ist.

Es wird nicht berücksichtigt, ob das <body>(oder vielleicht <html>) ein tabIndexAttribut hatte und somit tatsächlich fokussiert werden könnte . Wenn Sie eine Bibliothek oder etwas anderes schreiben und möchten, dass es robust ist, sollten Sie das wahrscheinlich irgendwie handhaben.


Hier ist eine ( schwere Airquotes) "Einzeiler" -Version des Erhaltens des fokussierten Elements, die konzeptionell komplizierter ist, weil Sie über Kurzschlüsse Bescheid wissen müssen, und Sie wissen, dass es offensichtlich nicht in eine Zeile passt, vorausgesetzt, Sie möchte, dass es lesbar ist.
Ich werde diesen nicht empfehlen. Aber wenn Sie ein 1337 hax0r sind, Idk ... ist es da.
Sie können das || nullTeil auch entfernen, wenn Sie falsein einigen Fällen nichts dagegen haben. (Sie könnten immer noch bekommen, nullwenn es document.activeElementist null):

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

Wenn ein bestimmtes Element zur Überprüfung fokussiert ist, alternativ Sie können Ereignisse verwenden, aber auf diese Weise erfordert Setup (und möglicherweise Teardown) und wichtiger ist , übernimmt ein Anfangszustand :

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

Sie können die Annahme des Anfangszustands auf nicht ereignisgesteuerte Weise korrigieren, aber Sie können dies auch verwenden.

1j01
quelle
15

document.activeElementkann standardmäßig das <body>Element verwenden, wenn keine fokussierbaren Elemente im Fokus sind. Wenn ein Element fokussiert ist und das Browserfenster unscharf ist, activeElementwird das fokussierte Element weiterhin beibehalten.

Wenn eines dieser beiden Verhaltensweisen nicht wünschenswert ist, ziehen Sie einen CSS-basierten Ansatz in Betracht : document.querySelector( ':focus' ).

Nate Whittaker
quelle
Cool, ja in meinem Fall hat dein Ansatz absolut Sinn gemacht. Ich kann meine fokussierbaren Elemente mit 'tabindex = "- 1"' festlegen. Wenn keines von ihnen den Fokus hat (z. B. Text oder Bilder, die mir egal sind), gibt document.querySelector (': focus') zurück Null.
Manfred
Siehe meine Antwort, um die Verwendung zu vermeiden querySelector: stackoverflow.com/a/40873560/2624876
1j01
10

Ich mochte den Ansatz von Joel S, aber ich liebe auch die Einfachheit von document.activeElement. Ich habe jQuery verwendet und beide kombiniert. Ältere Browser nicht unterstützen , document.activeElementwird verwenden Sie jQuery.data()den Wert von ‚hasFocus‘ zu speichern. Neuere Browser werden verwendet document.activeElement. Ich gehe davon aus, dass dies document.activeElementeine bessere Leistung bringen wird.

(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);
Jason
quelle
3
Könnte dies durch @William Denniss ersetzt werden $("*:focus")?
Pylinux
Ich nehme an, es könnte. Ich habe das vor langer Zeit geschrieben und hatte nie einen Grund, eine bessere Lösung zu überdenken, jetzt, wo es 5 Jahre später ist. Versuch es! Ich könnte genauso machen. Ich habe weniger Plugin auf unserer Seite! :) :)
Jason
10

Ein kleiner Helfer, den ich in Mootools für diese Zwecke verwendet habe:

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

Auf diese Weise können Sie überprüfen, ob das Element den Fokus hat, el.hasFocus()sofern startFocusTracking()dies für das angegebene Element aufgerufen wurde.

Joel S.
quelle
7

JQuery unterstützt die :focusPseudoklasse ab dem aktuellen Stand. Wenn Sie in der JQuery-Dokumentation danach suchen, überprüfen Sie unter "Selektoren", wo Sie auf die W3C-CSS-Dokumente verweisen . Ich habe mit Chrome, FF und IE 7+ getestet. Beachten Sie, dass es <!DOCTYPE...auf der HTML-Seite vorhanden sein muss , damit es im IE funktioniert . In diesem Beispiel wird davon ausgegangen, dass Sie dem fokussierten Element eine ID zugewiesen haben:

$(":focus").each(function() {
  alert($(this).attr("id") + " has focus!");
});
DeezCashews
quelle
1
Sie sollten (immer?) this.idAnstelle von $(this).attr('id')oder zumindest (wenn Sie Ihr jQuery-Objekt bereits haben) verwenden $(this)[0].id. Native Javascript auf dieser Ebene ist viel schneller und effizienter. Ist in diesem Fall möglicherweise nicht erkennbar, aber systemweit werden Sie einen Unterschied feststellen.
Martijn
7

Wenn Sie ein Objekt erhalten möchten, das eine Instanz von ist Element, müssen Sie es verwenden document.activeElement. Wenn Sie jedoch ein Objekt erhalten möchten, das eine Instanz von ist Text, müssen Sie es verwendendocument.getSelection().focusNode .

Ich hoffe es hilft.

rplaurindo
quelle
Besser auf welche Weise?
1j01
Öffnen Sie den Inspektor Ihres Browsers, klicken Sie auf eine beliebige Stelle der Seite, document.getSelection().focusNode.parentElementtippen Sie darauf und tippen Sie auf die Eingabetaste. Danach vorbei document.activeElementund mach es gleich. ;)
rplaurindo
document.activeElement<textarea>document.getSelection().focusNode<td><textarea>document.getSelection().focusNode.parentElement<tr><td>
Wenn
Entschuldigung, ich entschuldige mich. Ich habe es nicht gut erklärt. Wenn Sie ein Objekt erhalten möchten, das eine Instanz von ist Element, müssen Sie es verwenden document.activeElement. Wenn Sie jedoch ein Objekt erhalten möchten, das eine Instanz von ist Text, müssen Sie es verwenden document.getSelection().focusNode. Bitte testen Sie es erneut. Ich hoffe ich habe geholfen.
Rplaurindo
2
Die Frage ist, welches Element derzeit im Fokus steht. Und das focusNodeist garantiert auch kein Textknoten.
1j01
6

Es gibt potenzielle Probleme bei der Verwendung von document.activeElement. Erwägen:

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

Wenn sich der Benutzer auf ein inneres Div konzentriert, verweist document.activeElement weiterhin auf das äußere Div. Sie können document.activeElement nicht verwenden, um zu bestimmen, welcher der inneren Divs den Fokus hat.

Die folgende Funktion umgeht dies und gibt den fokussierten Knoten zurück:

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

Wenn Sie lieber das fokussierte Element erhalten möchten, verwenden Sie:

function active_element(){
  var anchor = window.getSelection().anchorNode;
  if(anchor.nodeType == 3){
        return anchor.parentNode;
  }else if(anchor.nodeType == 1){
        return anchor;
  }
}
Nathan K.
quelle
3
Das ist kein wirkliches Problem mit document.activeElement: Die inneren <div>Elemente können tatsächlich keinen Fokus erhalten, wie Sie visuell sehen können, indem Sie die Pseudoklasse:focus auf etwas Sichtbares setzen (Beispiel: jsfiddle.net/4gasa1t2/1 ). Sie sprechen davon, welches der inneren <div>s die Auswahl oder das Caret enthält, was ein separates Thema ist.
Tim Down
6

Ich habe festgestellt, dass das folgende Snippet nützlich ist, um festzustellen, welches Element derzeit den Fokus hat. Kopieren Sie Folgendes in die Konsole Ihres Browsers und drucken Sie jede Sekunde die Details des aktuellen Elements aus, das den Fokus hat.

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

Sie können das ändern console.log, um etwas anderes abzumelden, damit Sie das genaue Element genau bestimmen können, wenn das Ausdrucken des gesamten Elements Ihnen nicht hilft, das Element genau zu bestimmen.

vegemite4me
quelle
5

Es scheint, andere Antworten zu lesen und mich selbst zu versuchen document.activeElement das Element, das Sie in den meisten Browsern benötigen.

Wenn Sie einen Browser haben, der document.activeElement nicht unterstützt, wenn Sie über jQuery verfügen, sollten Sie in der Lage sein, ihn bei allen Fokusereignissen mit etwas sehr Einfachem wie diesem zu füllen (ungetestet, da ich keinen Browser habe, der diese Kriterien erfüllt ):

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
  });
}
rjmunro
quelle
5

Wenn Sie jQuery verwenden, können Sie damit herausfinden, ob ein Element aktiv ist:

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

Mit dojo können Sie dijit.getFocus () verwenden

Daniel Hartmann
quelle
3

Setzen Sie dies hier ein, um die Lösung zu finden, die ich schließlich gefunden habe.

Ich habe eine Eigenschaft namens document.activeInputArea erstellt und das HotKeys-Addon von jQuery verwendet, um Tastaturereignisse für Pfeiltasten, Tabulatoren und Eingaben abzufangen, und einen Ereignishandler zum Klicken in Eingabeelemente erstellt.

Dann habe ich die activeInputArea jedes Mal angepasst, wenn sich der Fokus geändert hat, damit ich diese Eigenschaft verwenden kann, um herauszufinden, wo ich mich befinde.

Es ist jedoch einfach, dies zu vermasseln, denn wenn Sie einen Fehler im System haben und der Fokus nicht dort liegt, wo Sie denken, ist es sehr schwierig, den richtigen Fokus wiederherzustellen.

Tony Peterson
quelle