Usando jQuery para probar si una entrada tiene foco


561

En la página principal de un sitio que estoy construyendo, varios <div>usan la pseudoclase CSS :hoverpara agregar un borde cuando el mouse está sobre ellos. Una de las <div>s contiene una <form>que, usando jQuery, mantendrá el borde si una entrada dentro tiene foco. Esto funciona perfectamente, excepto que IE6 no admite :hoverningún elemento que no sea <a>s. Entonces, para este navegador solo estamos usando jQuery para imitar CSS :hoverusando el $(#element).hover()método. El único problema es que ahora que jQuery maneja tanto el formulario focus() y hover() , cuando una entrada tiene el foco, el usuario mueve el mouse hacia adentro y hacia afuera, el borde desaparece.

Estaba pensando que podríamos usar algún tipo de condicional para detener este comportamiento. Por ejemplo, si probamos con el mouse fuera si alguna de las entradas tenía foco, podríamos evitar que el borde desaparezca. AFAIK, no hay un :focusselector en jQuery, así que no estoy seguro de cómo hacer que esto suceda. ¿Algunas ideas?


1
¿Puedes intentar reducirlo a unas pocas oraciones de lo que se requiere y de lo que estoy sucediendo?
mkoryak

Creo que debe considerar capturar el foco y desenfocar eventos ( docs.jquery.com/Events/focus y docs.jquery.com/Events/blur )
Wolfr

Publiqué una respuesta a la pregunta relacionada "¿Hay un 'foco' en JavaScript (o jQuery)?" . He mejorado [enfoque cletus citado por gnarf] (# 2684561).
luiggitama

Respuestas:


928

jQuery 1.6+

jQuery agregó un :focusselector para que ya no necesitemos agregarlo nosotros mismos. Solo usa$("..").is(":focus")

jQuery 1.5 y abajo

Editar: a medida que cambian los tiempos, encontramos mejores métodos para probar el enfoque, el nuevo favorito es esta esencia de Ben Alman :

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

Citado de Mathias Bynens aquí :

Tenga en cuenta que la (elem.type || elem.href)prueba se agregó para filtrar falsos positivos como el cuerpo. De esta manera, nos aseguramos de filtrar todos los elementos, excepto los controles de formulario y los hipervínculos.

Estás definiendo un nuevo selector. Ver Complementos / Autoría . Entonces puedes hacer:

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

o:

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

Cualquier jQuery

Si solo desea averiguar qué elemento tiene foco, puede usar

$(document.activeElement)

Si no está seguro de si la versión será 1.6 o inferior, puede agregar el :focusselector si falta:

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

44
Esto puede causar falsos positivos. Consulte stackoverflow.com/questions/967096/… para obtener más información (gracias a Ben Alman y Diego Perini).
Mathias Bynens

@Mathias Bynens - Gracias por la actualización (eres más que bienvenido para editar el wiki respuesta de la comunidad por cierto!)
gnarf

¿Qué pasa cuando lo necesitas para trabajar con 1.5 y 1.6? No quiero anular el propio selector de enfoque de jQuery. Algo como if (!jQuery.expr[':'].focus) { /* gist from Ben Alman */ }?
Betamos

@betamos - Exactamente correcto ... Agregaré algo en la respuesta para reflejar eso.
Gnarf

2
@Alex: proporcione un caso de prueba reducido en jsFiddle que muestre el problema, porque hasta donde puedo decir, no hay ninguna razón para que esto no funcione en elementos "dinámicos". Llamo travesuras ...
Gnarf

46

CSS:

.focus {
    border-color:red;
}

JQuery:

  $(document).ready(function() {

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

22

Aquí hay una respuesta más sólida que la actualmente aceptada:

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

Tenga en cuenta que la (elem.type || elem.href)prueba se agregó para filtrar falsos positivos como body. De esta manera, nos aseguramos de filtrar todos los elementos, excepto los controles de formulario y los hipervínculos.

(Tomado de esta esencia por Ben Alman ).


13

Actualización de abril de 2015

Dado que esta pregunta ha existido desde hace un tiempo, y algunas convenciones nuevas han entrado en juego, creo que debería mencionar que el .livemétodo se ha depreciado.

En su lugar, .onahora se ha introducido el método.

Su documentación es bastante útil para explicar cómo funciona;

El método .on () adjunta controladores de eventos al conjunto de elementos actualmente seleccionado en el objeto jQuery. A partir de jQuery 1.7, el método .on () proporciona toda la funcionalidad necesaria para adjuntar controladores de eventos. Para obtener ayuda en la conversión de métodos de eventos jQuery anteriores, consulte .bind (), .delegate () y .live ().

Entonces, para que pueda apuntar al evento 'enfocado en la entrada', puede usar esto en un script. Algo como:

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

Esto es bastante robusto e incluso le permite usar la tecla TAB también.


2

No estoy completamente seguro de lo que está buscando, pero parece que se puede lograr almacenando el estado de los elementos de entrada (¿o el div?) Como una 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;
        });
});

Esto es lo que terminé haciendo, pero usé una clase CSS arbitraria en lugar de una variable global de JavaScript.
bloudermilk

Usé una variación de esto. No se necesita un nuevo complemento jQuery. ¡Eso me hace una caravana feliz!
Dennis Day

1

Una alternativa al uso de clases para marcar el estado de un elemento es la funcionalidad interna del almacén de datos .

PD: Puedes almacenar booleanos y lo que quieras usando la data()función. No se trata solo de cadenas :)

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

Y luego es solo cuestión de acceder al estado de los elementos.



1

¿Has pensado en usar mouseOver y mouseOut para simular esto? También mire mouseEnter y mouseLeave


Eso es esencialmente lo que estoy haciendo con el hover de jQuery. Proporciona dos funciones, una para el mouse y otra para el mouse.
bloudermilk

0

Realice un seguimiento de ambos estados (suspendido, enfocado) como indicadores de verdadero / falso, y cada vez que uno cambie, ejecute una función que elimine el borde si ambos son falsos, de lo contrario, muestra el borde.

Entonces: conjuntos de enfoque enfocados = verdadero, conjuntos de desenfoque enfocados = falso. onmouseover establece hovered = true, onmouseout establece hovered = false. Después de cada uno de estos eventos, ejecute una función que agrega / elimina borde.


0

Hasta donde yo sé, no puede preguntarle al navegador si alguna entrada en la pantalla tiene foco, debe configurar algún tipo de seguimiento de foco.

Por lo general, tengo una variable llamada "noFocus" y la configuro como verdadera. Luego agrego un evento de enfoque a todas las entradas que hace que noFocus sea falso. Luego agrego un evento de desenfoque a todas las entradas que vuelven a establecer noFocus a verdadero.

Tengo una clase MooTools que maneja esto con bastante facilidad, estoy seguro de que podría crear un complemento jquery para hacer lo mismo.

Una vez que se haya creado, puede verificar noFocus antes de realizar cualquier intercambio de bordes.




0

Tuve un evento .live ("foco") configurado para seleccionar () (resaltar) el contenido de una entrada de texto para que el usuario no tuviera que seleccionarlo antes de escribir un nuevo valor.

$ (formObj) .select ();

Debido a las peculiaridades entre los diferentes navegadores, la selección a veces sería reemplazada por el clic que lo causó, y anularía la selección del contenido inmediatamente después a favor de colocar el cursor dentro del campo de texto (funcionó principalmente bien en FF pero falló en IE)

Pensé que podría resolver esto poniendo un ligero retraso en la selección ...

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

Esto funcionó bien y la selección persistiría, pero surgió un problema extraño. Si tabulaba de un campo al siguiente, el foco cambiaría al siguiente campo antes de que se realizara la selección. Dado que select roba el foco, el foco volverá y desencadenará un nuevo evento de "foco". Esto terminó en una cascada de selecciones de entrada bailando por toda la pantalla.

Una solución viable sería verificar que el campo aún tenga el foco antes de ejecutar select (), pero como se mencionó, no hay una manera simple de verificar ... Terminé simplemente prescindiendo de todo el resaltado automático, en lugar de activar lo que debería ser una sola llamada jQuery select () a una gran función cargada de subrutinas ...


0

Lo que terminé haciendo es crear una clase arbitraria llamada .elementhasfocus que se agrega y elimina dentro de la función jQuery focus (). Cuando la función hover () se ejecuta con el mouse fuera, busca .elementhasfocus:

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

Entonces, si no tiene esa clase (léase: ningún elemento dentro del div tiene foco), se elimina el borde. De lo contrario, no pasa nada.


-2

Simple

 <input type="text" /> 



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

    alert("I am in Focus");

     });
 </script>

Eso no te dice qué elemento está actualmente en foco. Se llama cuando un nuevo elemento obtiene el foco. Entonces, si un elemento ya tiene el foco y desea saber si 'este' es el indicado, este código es inútil.
Alexis Wilke
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.