web-dev-qa-db-fra.com

Comment savoir quel élément DOM a le focus?

J'aimerais savoir, en JavaScript, quel élément a actuellement le focus. J'ai parcouru le DOM et je n'ai pas encore trouvé ce dont j'avais besoin. Y a-t-il un moyen de faire cela, et comment?

La raison pour laquelle je cherchais ceci:

J'essaie de faire en sorte que des touches telles que les flèches et enter parcourent un tableau d'éléments d'entrée. Onglet fonctionne maintenant, mais entrez et les flèches ne semblent pas par défaut. La partie de gestion des clés est configurée, mais je dois maintenant comprendre comment déplacer le focus dans les fonctions de gestion des événements.

1201
Tony Peterson

Utilisez document.activeElement , il est pris en charge par tous les principaux navigateurs.

Auparavant, vous ne pouviez pas rechercher le type de champ de formulaire sélectionné. Pour émuler la détection dans les anciens navigateurs, ajoutez un gestionnaire d'événements "focus" à tous les champs et enregistrez le dernier champ ciblé dans une variable. Ajoutez un gestionnaire de "flou" pour effacer la variable lors d’un événement de flou pour le dernier champ ciblé.

Liens connexes:

1420
JW.

Comme l'a dit JW, vous ne pouvez pas trouver l'élément ciblé actuel, du moins de manière indépendante du navigateur. Mais si votre application est uniquement IE (certains le sont ...), vous pouvez la trouver de la manière suivante:

document.activeElement

EDIT: Il semble que IE n’ait pas tout à fait tort, cela fait partie du brouillon HTML5 et semble au moins être pris en charge par la dernière version de Chrome, Safari et Firefox.

117
Wookai

Si vous pouvez utiliser jQuery, il prend désormais en charge: focus, assurez-vous simplement que vous utilisez la version 1.6+.

Cette déclaration vous permettra d'obtenir l'élément actuellement ciblé.

$(":focus")

De: Comment sélectionner un élément qui a le focus avec jQuery

78
William Denniss

document.activeElement est maintenant élément du brouillon de travail HTML5 , mais il peut ne pas encore être pris en charge par certains navigateurs non majeurs/mobiles/anciens. Vous pouvez revenir à querySelector (si cela est supporté). Il convient également de mentionner que document.activeElement renverra document.body si aucun élément n'est ciblé, même si la fenêtre du navigateur n'a pas le focus.

Le code suivant contournera ce problème et retombera sur querySelector pour un meilleur support.

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

Une autre chose à noter est la différence de performance entre ces deux méthodes. Interroger le document avec des sélecteurs sera toujours beaucoup plus lent que d'accéder à la propriété activeElement. Voir ceci test de jsperf.com .

42
Andy E

Par lui-même, document.activeElement peut toujours renvoyer un élément si le document n'est pas ciblé (et doncrien dans le documentest ciblé!)

Vouspeutvoulez ce comportement, ou ilpeutn'est pas important (par exemple, dans un événement keydown) , mais si vous avez besoin de savoir que quelque chose est réellement ciblé, vous pouvez également vérifier document.hasFocus() .

Ce qui suit vous donnera l'élément ciblé s'il en existe un, ou bien null.

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

Pour vérifier si un élémentspécifique/ a le focus, c'est plus simple:

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

Pour vérifier sirienest focalisé, c'est encore plus complexe:

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

Note sur la robustesse : Dans le code où il vérifie document.body et document.documentElement, certains navigateurs en renvoient une. ou null lorsque rien n'est focalisé.

Il ne permet pas de savoir si le <body> (ou peut-être <html>) avait un attribut tabIndex et quepourrait donc être focalisé. Si vous écrivez une bibliothèque ou quelque chose et que vous voulez qu'elle soit robuste, vous devriez probablement le gérer d'une manière ou d'une autre.


Voici une version (heavyairquotes) "one-liner" permettant d'obtenir l'élément ciblé, qui estplus complexe du point de vue conceptuelparce que vous devez savoir sur le court-circuit, et vous savez, cela ne tient évidemment pas sur une ligne, en supposant que vous voulez que ce soit lisible.
Je ne recommanderai pas celui-ci. Mais si vous êtes un 1337 hax0r, idk ... c'est là.
Vous pouvez également supprimer la partie || null si vous voulez bien obtenir false dans certains cas. (Vous pouvez toujours obtenir null si document.activeElement est null):

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

Pour vérifier si un élément spécifique est ciblé, vous pouvez également alterner les événementspourrait/, mais cette procédure nécessite une configuration (et éventuellement un démontage), et surtout,suppose un état initial:

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

Vous pouvez corriger l'hypothèse d'état initial en utilisant la méthode sans événement, mais vous pouvez également l'utiliser à la place.

17
1j01

document.activeElement peut utiliser par défaut l'élément <body> si aucun élément à mettre au point n'est actif. De plus, si un élément est activé et que la fenêtre du navigateur est floue, activeElement continuera de contenir l'élément sélectionné.

Si l’un ou l’autre de ces deux comportements n’est pas souhaitable, envisagez une approche basée sur CSS: document.querySelector( ':focus' ).

14
Nate Whittaker

J'ai aimé l'approche utilisée par Joel S, mais j'aime aussi la simplicité de document.activeElement. J'ai utilisé jQuery et combiné les deux. Les navigateurs plus anciens qui ne prennent pas en charge document.activeElement utiliseront jQuery.data() pour stocker la valeur de 'hasFocus'. Les nouveaux navigateurs utiliseront document.activeElement. Je suppose que document.activeElement aura de meilleures performances.

(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);
10
Jason

Un petit assistant que j'ai utilisé à ces fins dans 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);

De cette façon, vous pouvez vérifier si l'élément a le focus avec el.hasFocus() à condition que startFocusTracking() ait été appelé sur l'élément donné.

9
Joel S

JQuery prend en charge la pseudo-classe :focus dès le courant. Si vous le cherchez dans la documentation de JQuery, allez sous "Sélecteurs" où il vous indique docs CSS du W3C . J'ai testé avec Chrome, FF et IE 7+. Notez que pour que cela fonctionne dans IE, <!DOCTYPE... doit exister sur la page html. Voici un exemple en supposant que vous ayez attribué un identifiant à l'élément qui a le focus:

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

Si vous voulez obtenir un objet qui est une instance de Element, vous devez utiliser document.activeElement, mais si vous voulez obtenir un objet qui est une instance de Text, vous devez utiliser document.getSelection().focusNode.

J'espère que ça aide.

7
rplaurindo

L'utilisation de document.activeElement peut poser des problèmes. Considérer:

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

Si l'utilisateur se concentre sur une division interne, document.activeElement fait toujours référence à la division externe. Vous ne pouvez pas utiliser document.activeElement pour déterminer lequel des divs internes a le focus.

La fonction suivante contourne cela et renvoie le nœud ciblé:

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

Si vous préférez obtenir l'élément ciblé, utilisez:

function active_element(){
  var anchor = window.getSelection().anchorNode;
  if(anchor.nodeType == 3){
        return anchor.parentNode;
  }else if(anchor.nodeType == 1){
        return anchor;
  }
}
6
Nathan K

En lisant d'autres réponses et en essayant moi-même, il semble que document.activeElement vous fournisse l'élément dont vous avez besoin dans la plupart des navigateurs.

Si votre navigateur ne prend pas en charge document.activeElement et que jQuery est présent, vous devriez pouvoir le renseigner sur tous les événements de focus avec quelque chose de très simple comme celui-ci (non testé car je n'ai pas de navigateur répondant à ces critères). ):

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

Si vous utilisez jQuery, vous pouvez utiliser ceci pour savoir si un élément est actif:

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

Avec dojo, vous pouvez utiliser dijit.getFocus ()

4
Daniel Hartmann

J'ai trouvé l'extrait suivant utile pour essayer de déterminer quel élément a actuellement le focus. Copiez le texte suivant dans la console de votre navigateur et il affichera à chaque seconde les détails de l’élément actif sélectionné.

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

N'hésitez pas à modifier le console.log pour vous déconnecter de quelque chose de différent afin de vous aider à identifier exactement l'élément si l'impression de tout l'élément ne vous aide pas à identifier cet élément.

4
vegemite4me

Il suffit de mettre ceci ici pour donner la solution que j'ai finalement trouvée.

J'ai créé une propriété appelée document.activeInputArea et utilisé l'addon HotKeys de jQuery pour intercepter les événements de clavier pour les touches de direction, tabulation et entrée, et j'ai créé un gestionnaire d'événements permettant de cliquer sur les éléments d'entrée.

Ensuite, j'ai ajusté activeInputArea à chaque changement de focus afin de pouvoir utiliser cette propriété pour savoir où je me trouvais.

Cependant, il est facile de tout gâcher, car si vous avez un bogue dans le système et que le focus n'est pas là où vous pensez qu'il est, il est très difficile de rétablir le focus correct.

3
Tony Peterson