Używanie jQuery do testowania, czy wejście jest aktywne

561

Na pierwszej stronie witryny, którą tworzę, kilka osób <div>używa :hoverpseudoklasy CSS, aby dodać ramkę, gdy wskaźnik myszy znajduje się nad nimi. Jeden z nich <div>zawiera taki, <form>który przy użyciu jQuery zachowa ramkę, jeśli fokus w niej jest aktywny. Działa to doskonale, z tym że IE6 nie obsługuje :hoverżadnych elementów innych niż <a>s. Tak więc, tylko w tej przeglądarce używamy jQuery do naśladowania CSS :hoverprzy użyciu tej $(#element).hover()metody. Jedynym problemem jest to, że teraz, gdy jQuery obsługuje zarówno formularz, focus() a hover() gdy wejście jest zogniskowane, użytkownik przesuwa mysz do środka i na zewnątrz, ramka znika.

Myślałem, że możemy użyć jakiegoś warunkowego rozwiązania, aby zatrzymać to zachowanie. Na przykład, gdybyśmy przetestowali na myszy, czy którekolwiek z wejść miały fokus, moglibyśmy zatrzymać granicę. AFAIK, :focusw jQuery nie ma selektora, więc nie jestem pewien, jak to zrobić. Jakieś pomysły?

bloudermilk
źródło
1
czy możesz spróbować sprowadzić to do kilku zdań tego, co jest wymagane i co się dzieje?
mkoryak
Myślę, że musisz przyjrzeć się uchwyceniu zdarzeń skupienia i rozmycia ( docs.jquery.com/Events/focus i docs.jquery.com/Events/blur )
Wolfr
Zamieściłem odpowiedź na powiązane pytanie „Czy w JavaScript (lub jQuery) występuje„ focus ”?” . Ulepszyłem [podejście Cletus cytowane przez gnarf] (# 2684561).
luiggitama,

Odpowiedzi:

928

jQuery 1.6+

jQuery dodał :focusselektor, więc nie musimy już dodawać go samodzielnie. Po prostu użyj$("..").is(":focus")

jQuery 1.5 i poniżej

Edycja: W miarę upływu czasu znajdujemy lepsze metody testowania fokusu, nowy faworyt to Ben Alman :

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

Cytat z Mathias Bynens tutaj :

Pamiętaj, że (elem.type || elem.href)test został dodany w celu odfiltrowania wyników fałszywie dodatnich, takich jak body. W ten sposób odfiltrowujemy wszystkie elementy oprócz formantów i hiperłączy.

Definiujesz nowy selektor. Zobacz Wtyczki / Authoring . Następnie możesz zrobić:

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

lub:

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

Wszelkie jQuery

Jeśli chcesz tylko dowiedzieć się, który element ma fokus, możesz użyć

$(document.activeElement)

Jeśli nie masz pewności, czy wersja będzie w wersji 1.6 lub niższej, możesz dodać :focusselektor, jeśli go brakuje:

(function ( $ ) {
    var filters = $.expr[":"];
    if ( !filters.focus ) { 
        filters.focus = function( elem ) {
           return elem === document.activeElement && ( elem.type || elem.href );
        };
    }
})( jQuery );
gnarf
źródło
4
Może to powodować fałszywe alarmy. Aby uzyskać więcej informacji, zobacz stackoverflow.com/questions/967096/ ... (dzięki Ben Alman i Diego Perini).
Mathias Bynens
@Mathias Bynens - Dziękujemy za aktualizację (zapraszamy do edycji tej wiki wiki, odpowiedź btw!)
gnarf
A kiedy potrzebujesz go do pracy zarówno z wersją 1.5, jak i 1.6? Nie chcę przesłonić własnego selektora fokusu jQuery. Coś takiego if (!jQuery.expr[':'].focus) { /* gist from Ben Alman */ }?
Betamos
@betamos - Dokładnie tak ... Dodam coś do odpowiedzi, aby to odzwierciedlić.
krasnal
2
@Alex - Proszę podać zredukowany przypadek testowy na jsFiddle pokazujący problem, ponieważ, o ile wiem, nie ma powodu, aby nie działał on na elementach „dynamicznych”. Nazywam shenanigans ...
Sznurek
46

CSS:

.focus {
    border-color:red;
}

JQuery:

  $(document).ready(function() {

    $('input').blur(function() {
        $('input').removeClass("focus");
      })
      .focus(function() {
        $(this).addClass("focus")
      });
  });
Daniel Moura
źródło
22

Oto bardziej niezawodna odpowiedź niż obecnie akceptowana:

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

Zauważ, że (elem.type || elem.href)test został dodany w celu odfiltrowania fałszywych alarmów, takich jak body. W ten sposób odfiltrowujemy wszystkie elementy oprócz formantów i hiperłączy.

(Zaczerpnięte z tej treści przez Ben Alman .)

Mathias Bynens
źródło
13

Aktualizacja z kwietnia 2015 r

Ponieważ pytanie to było już od jakiegoś czasu i zaczęły obowiązywać nowe konwencje, uważam, że powinienem wspomnieć, że .livemetoda została osłabiona.

Zamiast tego .onmetoda została wprowadzona.

Ich dokumentacja jest bardzo przydatna w wyjaśnianiu, jak to działa;

Metoda .on () dołącza procedury obsługi zdarzeń do aktualnie wybranego zestawu elementów w obiekcie jQuery. Począwszy od jQuery 1.7, metoda .on () zapewnia wszystkie funkcje wymagane do dołączania procedur obsługi zdarzeń. Aby uzyskać pomoc w konwersji starszych metod zdarzeń jQuery, zobacz .bind (), .delegate () i .live ().

Aby kierować na zdarzenie „skoncentrowane na danych wejściowych”, możesz użyć tego w skrypcie. Coś jak:

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

Jest to dość solidne i pozwala nawet na użycie klawisza TAB.

jbutler483
źródło
2

Nie jestem do końca pewien, czego szukasz, ale wydaje się, że można to osiągnąć, przechowując stan elementów wejściowych (lub div?) Jako zmienną:

$('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
źródło
Tak właśnie zrobiłem, ale użyłem dowolnej klasy CSS, a nie globalnej zmiennej javascript.
bloudermilk
Użyłem odmiany tego. Nie jest wymagana nowa wtyczka jQuery. To czyni mnie szczęśliwym obozowiczem!
Dzień Dennisa
1

Alternatywą dla używania klas do oznaczania stanu elementu jest funkcjonalność wewnętrznego magazynu danych .

PS: Możesz przechowywać booleany i cokolwiek zechcesz, korzystając z tej data()funkcji. Nie chodzi tylko o struny :)

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

A potem jest tylko kwestia dostępu do stanu elementów.

cllpse
źródło
1

Czy zastanawiałeś się nad użyciem mouseOver i mouseOut do symulacji tego. Zajrzyj także do mouseEnter i mouseLeave

mkoryak
źródło
Zasadniczo to właśnie robię z najechaniem kursorem jQuery. Dostarczasz dwie funkcje, jedną dla wejścia myszy i jedną dla wyjścia myszy.
bloudermilk
0

Śledź oba stany (uniesione, skupione) jako flagi prawda / fałsz, a gdy tylko jedna się zmieni, uruchom funkcję, która usuwa granicę, jeśli oba są fałszywe, w przeciwnym razie pokazuje granicę.

Tak więc: zestawy onfocus skoncentrowane = prawda, zestawy onblur skoncentrowane = fałsz. zestawy onmouseover hovered = true, zestawy onmouseout hovered = false. Po każdym z tych zdarzeń uruchom funkcję, która dodaje / usuwa granicę.

Blixt
źródło
0

O ile mi wiadomo, nie możesz zapytać przeglądarki, czy jakieś wejście na ekranie ma fokus, musisz skonfigurować śledzenie fokusa.

Zwykle mam zmienną o nazwie „noFocus” i ustawiam ją na true. Następnie dodaję zdarzenie focus do wszystkich danych wejściowych, które powodują, że noFocus jest fałszywy. Następnie dodaję zdarzenie rozmycia do wszystkich danych wejściowych, które ustawiły noFocus z powrotem na true.

Mam klasę MooTools, która radzi sobie z tym dość łatwo, jestem pewien, że możesz stworzyć wtyczkę jquery, aby zrobić to samo.

Po utworzeniu możesz sprawdzić noFocus przed zamianą granic.

Ryan Florence
źródło
0

Istnieje wtyczka do sprawdzania, czy element jest skoncentrowany: http://plugins.jquery.com/project/focused

$('input').each(function(){
   if ($(this) == $.focused()) {
      $(this).addClass('focused');
   }
})
Murat Çorlu
źródło
1
po co używać wtyczki, skoro można po prostu użyć rdzenia jquery?
Marcy Sutton
1
Masz rację. Ale 2 lata temu nie znałem rozwiązania tego problemu.
Murat Çorlu
0

Miałem zdarzenie .live („focus”), aby wybrać () (podświetlić) zawartość tekstu, aby użytkownik nie musiał go wybierać przed wpisaniem nowej wartości.

$ (formObj) .select ();

Z powodu dziwactw między różnymi przeglądarkami zaznaczenie czasami bywa zastępowane przez kliknięcie, które je spowodowało, i odznacza zawartość zaraz po tym, aby umieścić kursor w polu tekstowym (działało głównie dobrze w FF, ale nie działało w IE)

Myślałem, że mogę to rozwiązać, opóźniając wybrane ...

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

To działało dobrze i wybór trwał, ale pojawił się zabawny problem. Jeśli przejdziesz do jednego pola z drugiego, fokus przełączy się na następne pole, zanim nastąpi wybór. Ponieważ select kradnie fokus, fokus wróciłby i uruchomił nowe zdarzenie „fokus”. Skończyło się to kaskadą wybranych wejść tańczących na całym ekranie.

Realnym rozwiązaniem byłoby sprawdzenie, czy pole jest nadal aktywne przed wykonaniem select (), ale jak wspomniano, nie ma prostego sposobu sprawdzenia ... Skończyło się na tym, że zrezygnowałem z całego automatycznego podświetlania, zamiast obracać to, co powinno być jedno wywołanie jQuery select () do ogromnej funkcji pełnej podprogramów ...

Brian
źródło
0

Skończyło się na tym, że stworzyłem dowolną klasę o nazwie .elementhasfocus, która jest dodawana i usuwana w ramach funkcji focus () jQuery. Gdy funkcja hover () działa na myszy, sprawdza, czy występuje element .elementhasfocus:

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

Więc jeśli nie ma tej klasy (czytaj: żadne elementy w div nie mają fokusa), ramka jest usuwana. W przeciwnym razie nic się nie stanie.

bloudermilk
źródło
-2

Prosty

 <input type="text" /> 



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

    alert("I am in Focus");

     });
 </script>
Code Spy
źródło
To nie mówi ci, który element jest aktualnie ostry. Jest wywoływany, gdy nowy element zostaje skupiony. Więc jeśli element już ma fokus i chcesz wiedzieć, czy to „ten” jest ten, ten kod jest bezużyteczny.
Alexis Wilke