Verwenden von jQuery zum Testen, ob eine Eingabe den Fokus hat

561

Auf der Startseite einer Site, die ich erstelle, verwenden einige <div>die CSS :hover-Pseudoklasse, um einen Rahmen hinzuzufügen, wenn sich die Maus darüber befindet. Eines der <div>s enthält ein, <form>das mit jQuery den Rand beibehält, wenn eine Eingabe darin den Fokus hat. Dies funktioniert einwandfrei, außer dass IE6 keine :hoveranderen Elemente als <a>s unterstützt. Daher verwenden wir nur für diesen Browser jQuery, um CSS :hovermithilfe der $(#element).hover()Methode nachzuahmen . Das einzige Problem ist, dass jetzt, da jQuery sowohl das Formular verarbeitet focus() als hover() auch wenn eine Eingabe den Fokus hat, der Benutzer die Maus hinein und heraus bewegt, der Rand verschwindet.

Ich dachte, wir könnten eine Art Bedingung verwenden, um dieses Verhalten zu stoppen. Wenn wir beispielsweise mit der Maus testen, ob einer der Eingänge den Fokus hat, können wir verhindern, dass der Rand verschwindet. AFAIK, es gibt keinen :focusSelektor in jQuery, daher bin ich mir nicht sicher, wie ich das erreichen soll. Irgendwelche Ideen?

Blutmilch
quelle
1
Können Sie versuchen, das auf ein paar Sätze zu reduzieren, was erforderlich ist und was ich tue?
Mkoryak
Ich denke, Sie müssen sich mit der Erfassung der Fokus- und Unschärfeereignisse befassen ( docs.jquery.com/Events/focus und docs.jquery.com/Events/blur )
Wolfr
Ich habe eine Antwort auf die verwandte Frage "Gibt es in JavaScript (oder jQuery) einen" Has Focus "?" . Ich habe [von Gnarf zitierter Cletus-Ansatz] verbessert (# 2684561).
Luiggitama

Antworten:

928

jQuery 1.6+

jQuery hat einen :focusSelektor hinzugefügt, sodass wir ihn nicht mehr selbst hinzufügen müssen. Benutz einfach$("..").is(":focus")

jQuery 1.5 und niedriger

Bearbeiten: Wenn sich die Zeiten ändern, finden wir bessere Methoden zum Testen des Fokus. Der neue Favorit ist dieser Kern von Ben Alman :

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

Zitiert von Mathias Bynens hier :

Beachten Sie, dass der (elem.type || elem.href)Test hinzugefügt wurde, um falsch positive Ergebnisse wie den Körper herauszufiltern. Auf diese Weise stellen wir sicher, dass alle Elemente außer Formularsteuerelementen und Hyperlinks herausgefiltert werden.

Sie definieren einen neuen Selektor. Siehe Plugins / Authoring . Dann können Sie tun:

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

oder:

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

Jede jQuery

Wenn Sie nur herausfinden möchten, welches Element den Fokus hat, können Sie verwenden

$(document.activeElement)

Wenn Sie nicht sicher sind, ob die Version 1.6 oder niedriger sein wird, können Sie den :focusSelektor hinzufügen, wenn er fehlt:

(function ( $ ) {
    var filters = $.expr[":"];
    if ( !filters.focus ) { 
        filters.focus = function( elem ) {
           return elem === document.activeElement && ( elem.type || elem.href );
        };
    }
})( jQuery );
Gnarf
quelle
4
Dies kann zu Fehlalarmen führen. Weitere Informationen finden Sie unter stackoverflow.com/questions/967096/… (danke an Ben Alman und Diego Perini).
Mathias Bynens
@Mathias Bynens - Danke für das Update (du kannst diese Community-Wiki-Antwort übrigens gerne bearbeiten!)
gnarf
Was ist, wenn Sie es brauchen, um mit 1.5- und 1.6 zu arbeiten? Ich möchte den eigenen Fokus-Selektor von jQuery nicht überschreiben. So etwas wie if (!jQuery.expr[':'].focus) { /* gist from Ben Alman */ }?
Betamos
@betamos - Genau richtig ... Ich werde der Antwort etwas hinzufügen, um dies widerzuspiegeln.
Gnarf
2
@Alex - Bitte geben Sie einen reduzierten Testfall auf jsFiddle an, der das Problem zeigt, da es meines Erachtens keinen Grund gibt, warum dies bei "dynamischen" Elementen nicht funktionieren sollte . Ich nenne Shenanigans ...
Zwerg
46

CSS:

.focus {
    border-color:red;
}

JQuery:

  $(document).ready(function() {

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

Hier ist eine robustere Antwort als die derzeit akzeptierte:

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

Beachten Sie, dass der (elem.type || elem.href)Test hinzugefügt wurde, um falsch positive Ergebnisse wie herauszufiltern body. Auf diese Weise stellen wir sicher, dass alle Elemente außer Formularsteuerelementen und Hyperlinks herausgefiltert werden.

(Aus diesem Kern von Ben Alman entnommen .)

Mathias Bynens
quelle
13

April 2015 Update

Da diese Frage schon eine Weile besteht und einige neue Konventionen ins Spiel gekommen sind, sollte ich das erwähnen .live Methode abgeschrieben wurde.

An seiner Stelle die .on Methode eingeführt.

Ihre Dokumentation ist sehr nützlich, um zu erklären, wie es funktioniert.

Die Methode .on () hängt Ereignishandler an die aktuell ausgewählte Gruppe von Elementen im jQuery-Objekt an. Ab jQuery 1.7 bietet die .on () -Methode alle Funktionen, die zum Anhängen von Ereignishandlern erforderlich sind. Hilfe beim Konvertieren von älteren jQuery-Ereignismethoden finden Sie unter .bind (), .delegate () und .live ().

Damit Sie auf das Ereignis "Eingabeorientiert" abzielen können, können Sie dies in einem Skript verwenden. Etwas wie:

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

Dies ist ziemlich robust und ermöglicht es Ihnen sogar, die TAB-Taste zu verwenden.

jbutler483
quelle
2

Ich bin mir nicht ganz sicher, wonach Sie suchen, aber dies scheint zu erreichen, indem Sie den Status der Eingabeelemente (oder des div?) Als Variable speichern:

$('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
quelle
Dies ist, was ich getan habe, aber ich habe eine beliebige CSS-Klasse anstelle einer globalen Javascript-Variablen verwendet.
Bloudermilk
Ich habe eine Variation davon verwendet. Kein neues jQuery-Plugin erforderlich. Das macht mich zu einem glücklichen Camper!
Dennis Day
1

Eine Alternative zur Verwendung von Klassen zum Markieren des Status eines Elements ist die interne Datenspeicherfunktion .

PS: Mit der data()Funktion können Sie Boolesche Werte und alles, was Sie möchten, speichern . Es geht nicht nur um Strings :)

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

Und dann geht es nur noch darum, auf den Zustand der Elemente zuzugreifen.

cllpse
quelle
1

Haben Sie darüber nachgedacht, mouseOver und mouseOut zu verwenden, um dies zu simulieren ? Schauen Sie sich auch mouseEnter und mouseLeave an

mkoryak
quelle
Das ist im Wesentlichen das, was ich mit jQuerys Schwebeflug mache. Sie bieten zwei Funktionen, eine für die Mauseingabe und eine für die Mausausgabe.
Bloudermilk
0

Behalten Sie beide Zustände (schwebend, fokussiert) als wahr / falsch-Flags im Auge und führen Sie bei jeder Änderung eine Funktion aus, die den Rand entfernt, wenn beide falsch sind, andernfalls den Rand anzeigt.

Also: Onfocus-Sets fokussiert = wahr, Onblur-Sets fokussiert = falsch. onmouseover setzt hovered = true, onmouseout setzt hovered = false. Führen Sie nach jedem dieser Ereignisse eine Funktion aus, mit der Rahmen hinzugefügt / entfernt werden.

Blixt
quelle
0

Soweit ich weiß, können Sie den Browser nicht fragen, ob eine Eingabe auf dem Bildschirm den Fokus hat. Sie müssen eine Art Fokusverfolgung einrichten.

Normalerweise habe ich eine Variable namens "noFocus" und setze sie auf true. Dann füge ich allen Eingaben ein Fokusereignis hinzu, das noFocus falsch macht. Dann füge ich allen Eingaben, die noFocus auf true zurücksetzen, ein Unschärfeereignis hinzu.

Ich habe eine MooTools-Klasse, die dies recht einfach handhabt. Ich bin sicher, Sie könnten ein jquery-Plugin erstellen, um dasselbe zu tun.

Sobald dies erstellt wurde, können Sie noFocus überprüfen, bevor Sie einen Rahmenwechsel durchführen.

Ryan Florence
quelle
0

Es gibt ein Plugin, mit dem überprüft werden kann, ob ein Element fokussiert ist: http://plugins.jquery.com/project/focused

$('input').each(function(){
   if ($(this) == $.focused()) {
      $(this).addClass('focused');
   }
})
Murat Çorlu
quelle
1
Warum ein Plugin verwenden, wenn Sie nur Core JQuery verwenden können?
Marcy Sutton
1
Du hast recht. Aber ich wusste vor 2 Jahren keine Lösung für dieses Problem.
Murat Çorlu
0

Ich hatte ein .live-Ereignis ("Fokus") festgelegt, um den Inhalt einer Texteingabe auszuwählen () (hervorzuheben), damit der Benutzer ihn nicht auswählen muss, bevor er einen neuen Wert eingibt.

$ (formObj) .select ();

Aufgrund von Macken zwischen verschiedenen Browsern wurde die Auswahl manchmal durch den Klick ersetzt, der sie verursacht hat, und die Auswahl des Inhalts wurde sofort aufgehoben, um den Cursor in das Textfeld zu setzen (funktionierte in FF meistens in Ordnung, in IE jedoch fehlgeschlagen).

Ich dachte, ich könnte das lösen, indem ich die Auswahl etwas verzögere ...

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

Dies funktionierte gut und die Auswahl blieb bestehen, aber es trat ein lustiges Problem auf. Wenn Sie von einem Feld zum nächsten wechseln, wechselt der Fokus zum nächsten Feld, bevor die Auswahl erfolgt. Da select den Fokus stiehlt, würde der Fokus zurückgehen und ein neues "Fokus" -Ereignis auslösen. Dies endete in einer Kaskade von Eingabeauswahlen, die über den gesamten Bildschirm tanzten.

Eine praktikable Lösung wäre, vor dem Ausführen von select () zu überprüfen, ob das Feld noch fokussiert ist. Wie bereits erwähnt, gibt es jedoch keine einfache Möglichkeit, dies zu überprüfen. Am Ende habe ich nur auf die gesamte automatische Hervorhebung verzichtet, anstatt das zu drehen, was sein sollte Ein einzelner Aufruf von jQuery select () ruft eine riesige Funktion auf, die mit Unterprogrammen beladen ist ...

Brian
quelle
0

Am Ende habe ich eine beliebige Klasse namens .elementhasfocus erstellt, die innerhalb der Funktion jQuery focus () hinzugefügt und entfernt wird. Wenn die Funktion hover () mit der Maus ausgeführt wird, wird nach .elementhasfocus gesucht:

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

Wenn diese Klasse nicht vorhanden ist (lesen Sie: Keine Elemente innerhalb des Div haben den Fokus), wird der Rand entfernt. Sonst passiert nichts.

Blutmilch
quelle
-2

Einfach

 <input type="text" /> 



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

    alert("I am in Focus");

     });
 </script>
Code Spy
quelle
Das sagt Ihnen nicht, welches Element gerade im Fokus steht. Es wird aufgerufen, wenn ein neues Element den Fokus erhält. Wenn also ein Element bereits den Fokus hat und Sie wissen möchten, ob dies der Fall ist, ist dieser Code nutzlos.
Alexis Wilke