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

561

Sur la première page d'un site que je construis, plusieurs <div>utilisent la :hoverpseudo-classe CSS 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 en son sein a le focus. Cela fonctionne parfaitement sauf que IE6 ne prend en charge :hoveraucun élément autre que <a>s. Donc, pour ce navigateur uniquement, nous utilisons jQuery pour imiter CSS en :hoverutilisant la $(#element).hover()méthode. Le seul problème est, maintenant que jQuery gère à la fois le formulaire focus() et hover() , lorsqu'une entrée a le focus, l'utilisateur déplace la souris vers l'intérieur et vers l'extérieur, la bordure disparaît.

Je pensais que nous pourrions utiliser une sorte de conditionnel pour arrêter ce comportement. Par exemple, si nous testions à la souris si l'une des entrées avait le focus, nous pourrions empêcher la frontière de disparaître. AFAIK, il n'y a pas de :focussélecteur dans jQuery, donc je ne sais pas comment y arriver. Des idées?

lait flou
la source
1
pouvez-vous essayer de résumer cela en quelques phrases de ce qui est requis et de ce qui se passe?
mkoryak
Je pense que vous devez examiner la capture des événements de mise au point et de flou ( docs.jquery.com/Events/focus et docs.jquery.com/Events/blur )
Wolfr
J'ai posté une réponse à la question connexe "Existe-t-il un" a focus "en JavaScript (ou jQuery)?" . J'ai amélioré [l'approche cletus citée par gnarf] (# 2684561).
luiggitama

Réponses:

928

jQuery 1.6+

jQuery a ajouté un :focussélecteur afin que nous n'ayons plus besoin de l'ajouter nous-mêmes. Utilisez simplement$("..").is(":focus")

jQuery 1.5 et inférieur

Edit: Au fur et à mesure que les temps changent, nous trouvons de meilleures méthodes pour tester la concentration, le nouveau favori est cet essentiel de Ben Alman :

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

Cité par Mathias Bynens ici :

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

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

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

ou:

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

Any jQuery

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

$(document.activeElement)

Si vous n'êtes pas sûr si la version sera 1.6 ou inférieure, vous pouvez ajouter le :focussélecteur s'il manque:

(function ( $ ) {
    var filters = $.expr[":"];
    if ( !filters.focus ) { 
        filters.focus = function( elem ) {
           return elem === document.activeElement && ( elem.type || elem.href );
        };
    }
})( jQuery );
gnarf
la source
4
Cela peut provoquer des faux positifs. Voir stackoverflow.com/questions/967096/… pour plus d'informations (merci à Ben Alman et Diego Perini).
Mathias Bynens
@Mathias Bynens - Merci pour la mise à jour (vous êtes plus que bienvenus pour éditer cette réponse wiki communautaire btw!)
gnarf
Qu'en est-il lorsque vous en avez besoin pour travailler avec les versions 1.5 et 1.6? Je ne veux pas remplacer le propre sélecteur de focus de jQuery. Quelque chose comme ça if (!jQuery.expr[':'].focus) { /* gist from Ben Alman */ }?
Betamos
@betamos - Exactement bien ... Je vais ajouter quelque chose dans la réponse pour refléter cela.
gnarf
2
@Alex - Veuillez fournir un cas de test réduit sur jsFiddle montrant le problème, car pour autant que je sache, il n'y a aucune raison pour que cela ne fonctionne pas sur les éléments "dynamiques". J'appelle des manigances ...
gnarf
46

CSS:

.focus {
    border-color:red;
}

JQuery:

  $(document).ready(function() {

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

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 (elem.type || elem.href)test a été ajouté pour filtrer les faux positifs comme body. De cette façon, nous nous assurons de filtrer tous les éléments à l'exception des contrôles de formulaire et des hyperliens.

(Tiré de cet essentiel de Ben Alman .)

Mathias Bynens
la source
13

Mise à jour d'avril 2015

Étant donné que cette question existe depuis un certain temps et que de nouvelles conventions sont entrées en jeu, je pense que je dois mentionner que la .liveméthode a été dépréciée.

À sa place, la .onméthode a maintenant été introduite.

Leur documentation est très utile pour expliquer comment cela fonctionne;

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 à partir d'anciennes méthodes d'événement jQuery, consultez .bind (), .delegate () et .live ().

Donc, pour que vous puissiez cibler l'événement «focalisé sur l'entrée», vous pouvez l'utiliser dans un script. Quelque chose comme:

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

C'est assez robuste et vous permet même d'utiliser la touche TAB également.

jbutler483
la source
2

Je ne suis pas tout à fait sûr de ce que vous recherchez, mais cela semble pouvoir être obtenu en stockant l'état des éléments d'entrée (ou la div?) En tant que 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;
        });
});
James
la source
C'est ce que j'ai fini par faire, mais j'ai utilisé une classe CSS arbitraire plutôt qu'une variable javascript globale.
bloudermilk
J'en ai utilisé une variante. Aucun nouveau plugin jQuery nécessaire. Cela fait de moi un campeur heureux!
Dennis Day
1

Une alternative à l'utilisation de classes pour marquer l'état d'un élément est la fonctionnalité de stockage de données interne .

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

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

Et puis, il s'agit simplement d'accéder à l'état des éléments.

cllpse
la source
1

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

mkoryak
la source
C'est essentiellement ce que je fais avec le survol de jQuery. Vous fournissez deux fonctions, une pour l'entrée de la souris et l'autre pour la sortie de la souris.
bloudermilk
0

Gardez une trace des deux états (survolés, concentrés) en tant que drapeaux vrai / faux, et chaque fois que l'on change, exécutez une fonction qui supprime la bordure si les deux sont faux, sinon affiche la bordure.

Donc: les ensembles onfocus focalisés = vrai, les ensembles onblur focalisés = 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.

Blixt
la source
0

Pour autant que je sache, vous ne pouvez pas demander au navigateur si une entrée sur l'écran a le focus, vous devez configurer une sorte de suivi du focus.

J'ai généralement une variable appelée "noFocus" et je l'ai définie sur true. Ensuite, j'ajoute un événement focus à toutes les entrées qui rend faux noFocus. Ensuite, j'ajoute un événement flou à toutes les entrées qui redéfinissent noFocus sur true.

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

Une fois cela créé, vous pouvez vérifier noFocus avant de faire un échange de bordure.

Ryan Florence
la source
0

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

$('input').each(function(){
   if ($(this) == $.focused()) {
      $(this).addClass('focused');
   }
})
Murat Çorlu
la source
1
pourquoi utiliser un plugin alors que vous pouvez simplement utiliser core jquery?
Marcy Sutton
1
Tu as raison. Mais je ne connaissais pas de solution à ce problème il y a 2 ans.
Murat Çorlu
0

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

$ (formObj) .select ();

En raison de bizarreries entre différents navigateurs, la sélection était parfois remplacée par le clic qui l'avait provoqué, et elle désélectionnait le contenu juste après en faveur de placer le curseur dans le champ de texte (fonctionnait surtout bien dans FF mais a échoué dans IE)

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

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

Cela a bien fonctionné et la sélection persisterait, mais un drôle de problème est survenu. Si vous tabuliez d'un champ à l'autre, le focus passait au champ suivant avant que la sélection n'ait lieu. Puisque select vole le focus, le focus reviendrait alors et déclencherait un nouvel événement "focus". Cela s'est terminé par une cascade de sélections d'entrée dansant sur tout l'écran.

Une solution réalisable serait de vérifier que le champ a toujours le focus avant d'exécuter la sélection (), mais comme mentionné, il n'y a pas de moyen simple de vérifier ... un seul appel jQuery select () dans une énorme fonction chargée de sous-programmes ...

Brian
la source
0

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 recherche .elementhasfocus:

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

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

lait flou
la source
-2

Facile

 <input type="text" /> 



 <script>
     $("input").focusin(function() {

    alert("I am in Focus");

     });
 </script>
Code Spy
la source
Cela ne vous dit pas quel élément est actuellement au point. Il est appelé lorsqu'un nouvel élément obtient le focus. Donc, si un élément a déjà le focus et que vous voulez savoir si «c'est», ce code est inutile.
Alexis Wilke