Usando jQuery para probar si una entrada tiene foco

580

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. Uno de los <div>s contiene un <form>que, usando jQuery, mantendrá el borde si una entrada dentro de él tiene foco. Esto funciona perfectamente, excepto que IE6 no es compatible :hovercon ningún elemento que no sea <a>s. Entonces, solo para este navegador usamos 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 hacia afuera si alguna de las entradas tiene el 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?

3
960

jQuery 1.6+

jQuery agregó un :focusselector, por lo que ya no necesitamos agregarlo nosotros mismos. Solo usa$("..").is(":focus")

jQuery 1.5 y por debajo

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í :

Note that the (elem.type || elem.href) test was added to filter out false positives like body. This way, we make sure to filter out all elements except form controls and hyperlinks.

Estás definiendo un nuevo selector. Consulte Complementos / Creación . Entonces puedes hacer:

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

o:

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

Cualquier jQuery

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

$(document.activeElement)

Si no está seguro de si la versión será 1.6 o anterior, 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 );
8
  • 4
    Esto puede provocar falsos positivos. Consulte stackoverflow.com/questions/967096/… para obtener más información (gracias a Ben Alman y Diego Perini). Mathias Bynens 22/03/11 a las 13:01
  • @Mathias Bynens - Gracias por la actualización (¡eres más que bienvenido a editar esta respuesta wiki de la comunidad por cierto!)gnarf 22/03/11 a las 21:31
  • ¿Qué pasa cuando lo necesitas para trabajar tanto con 1.5 como con 1.6? No quiero anular el propio selector de enfoque de jQuery. Algo como if (!jQuery.expr[':'].focus) { /* gist from Ben Alman */ }? Betamos 3/06/11 a las 19:11
  • @betamos - Exactamente ... Agregaré algo en la respuesta para reflejar eso. gnarf 3/06/11 a las 20:51
  • 2
    @Alex: proporcione un caso de prueba reducido en jsFiddle que muestre el problema, porque hasta donde yo sé, no hay razón para que esto no funcione en elementos "dinámicos". Yo llamo travesuras ...gnarf 14/06/12 a las 22:14
47

CSS:

.focus {
    border-color:red;
}

JQuery:

  $(document).ready(function() {

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

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

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 ).

dieciséis

Actualización de abril de 2015

Dado que esta pregunta ha existido por un tiempo y han entrado en juego algunas convenciones nuevas, 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;

The .on() method attaches event handlers to the currently selected set of elements in the jQuery object. As of jQuery 1.7, the .on() method provides all functionality required for attaching event handlers. For help in converting from older jQuery event methods, see .bind(), .delegate(), and .live().

Entonces, para que pueda orientar el 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.

1
  • muy buena solución, gracias. Úselo on("focusout",para la función opuestaBarbz_YHOOL 19 ago.20 a las 23:30
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;
        });
});
2
  • Esto es lo que terminé haciendo, pero usé una clase CSS arbitraria en lugar de una variable global de JavaScript. bloudermilk 8 de junio de 2009 a las 21:42
  • Usé una variación de esto. No se necesita un nuevo complemento de jQuery. ¡Eso me hace un campista feliz! Dennis Day 8/11/10 a las 21:06
1

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

PD: Puede almacenar booleanos y lo que desee usando la data()función. No se trata solo de cuerdas :)

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

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

1

si a alguien le importa, hay una forma mucho mejor de captar la atención ahora, $(foo).focus(...)

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

0
1

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

1
  • Eso es esencialmente lo que estoy haciendo con el hover de jQuery. Proporciona dos funciones, una para el mouse hacia adentro y otra para el mouse hacia afuera. bloudermilk 8 de junio de 2009 a las 21:30
0

Realice un seguimiento de ambos estados (flotante, 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: onfocus establece focus = true, onblur establece focus = false. onmouseover establece hovered = true, onmouseout sets hovered = false. Después de cada uno de estos eventos, se ejecuta una función que agrega / elimina el borde.

0

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

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 configuran noFocus de nuevo a verdadero.

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

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

0

No hay: foco, pero sí: seleccionado http://docs.jquery.com/Selectors/selected

pero si desea cambiar el aspecto de las cosas en función de lo seleccionado, probablemente debería estar trabajando con los eventos de desenfoque.

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

0
0

Hay un complemento para verificar si un elemento está enfocado: http://plugins.jquery.com/project/focused

$('input').each(function(){
   if ($(this) == $.focused()) {
      $(this).addClass('focused');
   }
})
2
  • 1
    ¿Por qué usar un complemento cuando solo puede usar core jquery? Marcy Sutton 16/12/11 a las 18:40
  • 1
    Tienes razón. Pero no conocía una solución para este problema hace 2 años. Murat Çorlu 17/12/11 a las 22:04
0

Tenía un evento .live ("focus") 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 peculiaridades entre los diferentes navegadores, la selección a veces sería reemplazada por el clic que la causó, y anularía la selección del contenido justo 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 gracioso. Si pasaba de un campo al siguiente, el enfoque cambiaría al siguiente campo antes de que se realizara la selección. Dado que la selección roba el foco, el foco volvería y desencadenaría 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 todavía tenga el foco antes de ejecutar select (), pero como se mencionó, no hay una forma simple de verificar ... Terminé simplemente prescindiendo de todo el resaltado automático, en lugar de girar lo que debería ser una sola llamada jQuery select () en una función enorme cargada de subrutinas ...

0

Lo que terminé haciendo es crear una clase arbitraria llamada .elementhasfocus que se agrega y se elimina dentro de la función jQuery focus (). Cuando la función hover () se ejecuta con el mouse, 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), el borde se elimina. De lo contrario, no pasa nada.

-2

Sencillo

 <input type="text" /> 



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

    alert("I am in Focus");

     });
 </script>
1
  • Eso no le dice qué elemento está actualmente enfocado. Se llama cuando un nuevo elemento recibe 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 1 de febrero de 2014 a las 0:46