web-dev-qa-db-fra.com

Utilisation de jQuery pour tester si une entrée a le focus

Sur la page d'accueil d'un site que je suis en train de construire, plusieurs <div>s utilisent la pseudo-classe CSS :hover pour ajouter une bordure lorsque la souris les survole. L'un des <div>s contient un <form> qui, à l'aide de jQuery, conservera la bordure si une entrée à l'intérieur de celle-ci a le focus. Cela fonctionne parfaitement sauf que IE6 ne supporte pas :hover sur aucun élément autre que <a>s. Donc, pour ce navigateur uniquement, nous utilisons jQuery pour imiter CSS :hover en utilisant la méthode $(#element).hover(). Le seul problème est que, maintenant que jQuery gère à la fois le formulaire focus()ethover(), lorsqu'une entrée est activée, l'utilisateur déplace la souris à l'intérieur et à l'extérieur, la bordure disparaît.

Je pensais que nous pourrions utiliser une sorte de condition pour arrêter ce comportement. Par exemple, si nous vérifions avec la souris si l’une des entrées a le focus, nous pourrions empêcher la frontière de s’éloigner. Autant que je sache, il n'y a pas de sélecteur :focus dans jQuery, donc je ne sais pas comment faire pour que cela se produise. Des idées?

534
bloudermilk

jQuery 1.6+

jQuery a ajouté un sélecteur :focus , nous n'avons donc plus besoin de l'ajouter nous-mêmes. Il suffit d'utiliser $("..").is(":focus")

jQuery 1.5 et inférieur

Edit: À mesure que les temps changent, nous trouvons de meilleures méthodes de test de la focalisation, le nouveau favori est ce Gist de Ben Alman :

jQuery.expr[':'].focus = function( elem ) {
  return elem === document.activeElement && ( elem.type || elem.href );
};

Cité de Mathias Bynens ici :

Notez que le test (elem.type || elem.href) a été ajouté pour filtrer les faux positifs comme body. De cette façon, nous nous assurons de filtrer tous les éléments sauf les contrôles de formulaire et les hyperliens.

Vous définissez un nouveau sélecteur. Voir Plugins/Authoring . Ensuite, vous pouvez faire:

if ($("...").is(":focus")) {
  ...
}

ou:

$("input:focus").doStuff();

Tout jQuery

Si vous voulez juste savoir quel élément a le focus, vous pouvez utiliser

$(document.activeElement)

Si vous ne savez pas si la version sera 1.6 ou inférieure, vous pouvez ajouter le sélecteur :focus s'il est manquant:

(function ( $ ) {
    var filters = $.expr[":"];
    if ( !filters.focus ) { 
        filters.focus = function( elem ) {
           return elem === document.activeElement && ( elem.type || elem.href );
        };
    }
})( jQuery );
887
gnarf

CSS:

.focus {
    border-color:red;
}

JQuery:

  $(document).ready(function() {

    $('input').blur(function() {
        $('input').removeClass("focus");
      })
      .focus(function() {
        $(this).addClass("focus")
      });
  });
43
Daniel Moura

Voici une réponse plus robuste que celle actuellement acceptée:

jQuery.expr[':'].focus = function(elem) {
  return elem === document.activeElement && (elem.type || elem.href);
};

Notez que le test (elem.type || elem.href) a été ajouté pour filtrer les faux positifs tels que body. De cette façon, nous nous assurons de filtrer tous les éléments sauf les contrôles de formulaire et les hyperliens.

(Extrait de this Gist by Ben Alman .)

20
Mathias Bynens

Mise à jour d'avril 2015

Comme cette question existe depuis un certain temps et que de nouvelles conventions sont entrées en jeu, j'estime devoir mentionner la méthode .live qui a été amortie.

A sa place, la méthode .on a maintenant été introduite.

Leur documentation est très utile pour expliquer son fonctionnement.

La méthode .on () attache des gestionnaires d’événements à l’ensemble d’éléments actuellement sélectionné dans l’objet jQuery. Depuis jQuery 1.7, la méthode .on () fournit toutes les fonctionnalités requises pour attacher des gestionnaires d'événements. Pour obtenir de l'aide sur la conversion d'anciennes méthodes d'événement jQuery, voir .bind (), .delegate () et .live ().

Donc, pour que vous puissiez cibler l'événement 'axé sur les entrées', vous pouvez l'utiliser dans un script. Quelque chose comme:

$('input').on("focus", function(){
   //do some stuff
});

Ceci est assez robuste et vous permet même d’utiliser la touche TAB.

13
jbutler483

Je ne suis pas tout à fait sûr de ce que vous recherchez, mais cela semble pouvoir être réalisé en stockant l'état des éléments d'entrée (ou de la div?) Sous forme de variable:

$('div').each(function(){

    var childInputHasFocus = false;

    $(this).hover(function(){
        if (childInputHasFocus) {
            // do something
        } else { }
    }, function() {
        if (childInputHasFocus) {
            // do something
        } else { }
    });

    $('input', this)
        .focus(function(){
            childInputHasFocus = true;
        })
        .blur(function(){
            childInputHasFocus = false;
        });
});
2
James

si quelqu'un se soucie de lui, il existe un moyen bien meilleur de capturer le focus maintenant, $(foo).focus(...)

http://api.jquery.com/focus/

1
CrackSmoker9000

Une alternative à l’utilisation de classes pour marquer l’état d’un élément est l’interne fonctionnalité du magasin de données .

P.S .: Vous pouvez stocker des booléens et ce que vous désirez en utilisant la fonction data(). Ce n'est pas qu'une question de cordes :)

$("...").mouseover(function ()
{
    // store state on element
}).mouseout(function ()
{
    // remove stored state on element
});

Et ensuite, il suffit d'accéder à l'état des éléments.

1
cllpse

Avez-vous pensé à utiliser mouseOver et mouseOut pour simuler cela. Regardez aussi mouseEnter et mouseLeave

1
mkoryak

J'ai fini par créer une classe arbitraire appelée .elementhasfocus qui est ajoutée et supprimée dans la fonction jQuery focus (). Lorsque la fonction hover () s'exécute à la sortie de la souris, elle vérifie la présence de .elementhasfocus:

if(!$("#quotebox").is(".boxhasfocus")) $(this).removeClass("box_border");

Donc, s'il n'a pas cette classe (lire: aucun élément de la div n'a le focus), la bordure est supprimée. Sinon, rien ne se passe.

0
bloudermilk

Il existe un plugin pour vérifier si un élément est activé: http://plugins.jquery.com/project/focused

$('input').each(function(){
   if ($(this) == $.focused()) {
      $(this).addClass('focused');
   }
})
0
Murat Çorlu

J'avais un événement .live ("focus") configuré pour sélectionner () (mettre en surbrillance) le contenu d'une entrée de texte afin que l'utilisateur n'ait pas à le sélectionner avant de saisir une nouvelle valeur.

$ (formObj) .select ();

En raison de bizarreries entre différents navigateurs, la sélection était parfois remplacée par le clic qui la provoquait et elle désélectionnait le contenu juste après au lieu de placer le curseur dans le champ de texte (fonctionnait généralement en ok dans FF mais échouait dans IE)

Je pensais pouvoir résoudre ce problème en mettant un léger retard sur le ...

setTimeout (function () {$ (formObj) .select ();}, 200);

Cela fonctionnait bien et la sélection persistait, mais un problème amusant se posait. Si vous passez d’un champ à l’autre, la sélection passe au champ suivant avant la sélection. Dans la mesure où certains objets volés sont focalisés sur le focus, celui-ci revient en arrière et déclenche un nouvel événement "focus". Cela a abouti à une cascade d'entrées sélectionnant la danse sur tout l'écran.

Une solution viable consisterait à vérifier que le champ est toujours actif avant d'exécuter select (), mais comme indiqué, il n'existe pas de moyen simple de vérifier ... J'ai fini par me passer de la mise en surbrillance automatique au lieu de tourner ce qui devrait être un simple appel jQuery select () dans une fonction énorme chargée de sous-programmes ...

0
Brian

Gardez une trace des deux états (survolé, ciblé) comme indicateurs true/false et, chaque fois que vous changez, exécutez une fonction qui supprime la bordure si les deux sont faux, sinon affiche la bordure.

Donc: onfocus définit ciblé = vrai, onblur définit ciblé = faux. onmouseover définit hovered = true, onmouseout définit hovered = false. Après chacun de ces événements, exécutez une fonction qui ajoute/supprime la bordure.

0
Blixt

Autant que je sache, vous ne pouvez pas demander au navigateur si une entrée à l'écran a le focus, vous devez configurer une sorte de suivi de la mise au point.

J'ai généralement une variable appelée "noFocus" et la mettre à true. Ensuite, j'ajoute à toutes les entrées un événement de focus qui rend noFocus faux. Ensuite, j'ajoute un événement de flou à toutes les entrées qui remet noFocus à true.

J'ai une classe MooTools qui gère cela assez facilement, je suis sûr que vous pourriez créer un plugin jquery pour faire la même chose.

Une fois que cela est créé, vous pouvez vérifier noFocus avant d’échanger les bordures.

0
Ryan Florence

Il n'y a pas: focus, mais il y a: selected http://docs.jquery.com/Selectors/selected

mais si vous voulez changer l'apparence des choses en fonction de ce qui est sélectionné, vous devriez probablement travailler avec les événements de flou.

http://docs.jquery.com/Events/blur

0
Chris Brandsma