Me gustaría saber, en JavaScript, qué elemento tiene actualmente el foco. He estado buscando a través del DOM y aún no he encontrado lo que necesito. ¿Hay alguna manera de hacer esto, y cómo?

La razón por la que estaba buscando esto:

Estoy tratando de hacer teclas como las flechas y enternavegar a través de una tabla de elementos de entrada. La pestaña funciona ahora, pero ingrese, y las flechas no lo hacen por defecto, parece. Tengo configurada la parte de manejo de claves, pero ahora necesito descubrir cómo mover el foco en las funciones de manejo de eventos.

respuesta

Use document.activeElement, es compatible con todos los principales navegadores.

Anteriormente, si intentaba averiguar qué campo de formulario tiene el foco, no podía. Para emular la detección en navegadores más antiguos, agregue un controlador de eventos de "enfoque" a todos los campos y registre el último campo enfocado en una variable. Agregue un controlador de "desenfoque" para borrar la variable en un evento de desenfoque para el último campo enfocado.

Si necesita eliminar el activeElementpuede usar desenfoque; document.activeElement.blur(). Cambiará el activeElementa body.

Enlaces relacionados:

Como dijo JW, no puede encontrar el elemento enfocado actual, al menos de una manera independiente del navegador. Pero si su aplicación es solo para IE (algunas lo son...), puede encontrarla de la siguiente manera:

document.activeElement

Parece que IE no tenía todo mal después de todo, esto es parte del borrador de HTML5 y parece ser compatible con la última versión de Chrome, Safari y Firefox al menos.

Si puede usar jQuery, ahora es compatible con :focus, solo asegúrese de estar usando la versión 1.6+.

Esta declaración le dará el elemento enfocado actualmente.

$(":focus")

De: Cómo seleccionar un elemento que tiene foco en él con jQuery

document.activeElementahora es parte del borrador de especificación de trabajo de HTML5, pero es posible que aún no sea compatible con algunos navegadores no principales/móviles/antiguos. Puede recurrir a querySelector(si eso es compatible). También vale la pena mencionar que document.activeElementregresará document.bodysi no se enfoca ningún elemento, incluso si la ventana del navegador no tiene el foco.

El siguiente código solucionará este problema y retrocederá para querySelectorbrindar un poco mejor soporte.

var focused = document.activeElement;
if (!focused || focused == document.body)
    focused = null;
else if (document.querySelector)
    focused = document.querySelector(":focus");

Una cosa adicional a tener en cuenta es la diferencia de rendimiento entre estos dos métodos. Consultar el documento con selectores siempre será mucho más lento que acceder a la activeElementpropiedad. Vea esta prueba de jsperf.com .

Por sí mismo, document.activeElementaún puede devolver un elemento si el documento no está enfocado (¡y por lo tanto nada en el documento está enfocado!)

Es posible que desee ese comportamiento, o puede que no importe (por ejemplo, dentro de un keydownevento), pero si necesita saber que algo está realmente enfocado, también puede verificar document.hasFocus().

Lo siguiente le dará el elemento enfocado si hay uno, o de lo contrario null.

var focused_element = null;
if (
    document.hasFocus() &&
    document.activeElement !== document.body &&
    document.activeElement !== document.documentElement
) {
    focused_element = document.activeElement;
}

Para verificar si un elemento específico tiene foco, es más simple:

var input_focused = document.activeElement === input && document.hasFocus();

Para verificar si algo está enfocado, es más complejo nuevamente:

var anything_is_focused = (
    document.hasFocus() &&
    document.activeElement !== null &&
    document.activeElement !== document.body &&
    document.activeElement !== document.documentElement
);

Nota de robustez : en el código donde se verifica contra document.bodyy document.documentElement, esto se debe a que algunos navegadores devuelven uno de estos o nullcuando nada está enfocado.

No tiene en cuenta si <body>(o tal vez <html>) tenía un tabIndexatributo y, por lo tanto, podría enfocarse . Si está escribiendo una biblioteca o algo así y quiere que sea robusta, probablemente debería manejar eso de alguna manera.


Aquí hay una versión "de una sola línea" (comillas pesadas ) para obtener el elemento enfocado, que es conceptualmente más complicado porque tiene que saber sobre cortocircuitos, y ya sabes, obviamente no encaja en una línea, suponiendo que quiere que sea legible.
No voy a recomendar este. Pero si eres un 1337 hax0r, no sé... ahí está.
También puede quitar la || nullpieza si no le importa falseen algunos casos. (Aún podría obtener nullsi document.activeElementes null):

var focused_element = (
    document.hasFocus() &&
    document.activeElement !== document.body &&
    document.activeElement !== document.documentElement &&
    document.activeElement
) || null;

Para verificar si un elemento específico está enfocado, alternativamente podría usar eventos, pero de esta manera requiere configuración (y potencialmente desmontaje) y, lo que es más importante, asume un estado inicial :

var input_focused = false;
input.addEventListener("focus", function() {
    input_focused = true;
});
input.addEventListener("blur", function() {
    input_focused = false;
});

Puede corregir la suposición del estado inicial utilizando la forma sin eventos, pero también podría usar eso en su lugar.

document.activeElementpuede predeterminar el <body>elemento si no hay elementos enfocables en el foco. Además, si un elemento está enfocado y la ventana del navegador está borrosa, activeElementseguirá manteniendo el elemento enfocado.

Si alguno de estos dos comportamientos no es deseable, considere un enfoque basado en CSS: document.querySelector( ':focus' ).

He encontrado que el siguiente fragmento es útil cuando intento determinar qué elemento tiene el foco actualmente. Copie lo siguiente en la consola de su navegador, y cada segundo imprimirá los detalles del elemento actual que tiene el foco.

setInterval(function() { console.log(document.querySelector(":focus")); }, 1000);

Siéntase libre de modificar console.logpara cerrar sesión algo diferente para ayudarlo a identificar el elemento exacto si imprimir todo el elemento no lo ayuda a identificar el elemento.

Me gustó el enfoque utilizado por Joel S, pero también me encanta la simplicidad de document.activeElement. Usé jQuery y combiné los dos. Los navegadores más antiguos que no son compatibles document.activeElementutilizarán jQuery.data()para almacenar el valor de 'hasFocus'. Los navegadores más nuevos usarán document.activeElement. Supongo que document.activeElementtendrá un mejor rendimiento.

(function($) {
var settings;
$.fn.focusTracker = function(options) {
    settings = $.extend({}, $.focusTracker.defaults, options);

    if (!document.activeElement) {
        this.each(function() {
            var $this = $(this).data('hasFocus', false);

            $this.focus(function(event) {
                $this.data('hasFocus', true);
            });
            $this.blur(function(event) {
                $this.data('hasFocus', false);
            });
        });
    }
    return this;
};

$.fn.hasFocus = function() {
    if (this.length === 0) { return false; }
    if (document.activeElement) {
        return this.get(0) === document.activeElement;
    }
    return this.data('hasFocus');
};

$.focusTracker = {
    defaults: {
        context: 'body'
    },
    focusedElement: function(context) {
        var focused;
        if (!context) { context = settings.context; }
        if (document.activeElement) {
            if ($(document.activeElement).closest(context).length > 0) {
                focused = document.activeElement;
            }
        } else {
            $(':visible:enabled', context).each(function() {
                if ($(this).data('hasFocus')) {
                    focused = this;
                    return false;
                }
            });
        }
        return $(focused);
    }
};
})(jQuery);

Un pequeño ayudante que he usado para estos propósitos en Mootools:

FocusTracker = {
    startFocusTracking: function() {
       this.store('hasFocus', false);
       this.addEvent('focus', function() { this.store('hasFocus', true); });
       this.addEvent('blur', function() { this.store('hasFocus', false); });
    },

    hasFocus: function() {
       return this.retrieve('hasFocus');
    }
}

Element.implement(FocusTracker);

De esta manera, puede verificar si el elemento tiene el foco el.hasFocus()siempre que startFocusTracking()se haya llamado al elemento dado.

JQuery admite la :focuspseudoclase a partir de la actualidad. Si lo está buscando en la documentación de JQuery, verifique en "Selectores" donde lo señala a los documentos W3C CSS . He probado con Chrome, FF e IE 7+. Tenga en cuenta que para que funcione en IE, <!DOCTYPE...debe existir en la página html. Aquí hay un ejemplo, suponiendo que haya asignado una identificación al elemento que tiene el foco:

$(":focus").each(function() {
  alert($(this).attr("id") + " has focus!");
});

Si desea obtener un objeto que sea instancia de Element, debe usar document.activeElement, pero si desea obtener un objeto que sea instancia de Text, debe usar document.getSelection().focusNode.

Espero que ayude.

Si está usando jQuery, puede usar esto para averiguar si un elemento está activo:

$("input#id").is(":active");

Hay problemas potenciales con el uso de document.activeElement. Considerar:

<div contentEditable="true">
  <div>Some text</div>
  <div>Some text</div>
  <div>Some text</div>
</div>

Si el usuario se enfoca en un div interno, entonces document.activeElement todavía hace referencia al div externo. No puede usar document.activeElement para determinar cuál de los div internos tiene el foco.

La siguiente función soluciona esto y devuelve el nodo enfocado:

function active_node(){
  return window.getSelection().anchorNode;
}

Si prefiere obtener el elemento enfocado, use:

function active_element(){
  var anchor = window.getSelection().anchorNode;
  if(anchor.nodeType == 3){
        return anchor.parentNode;
  }else if(anchor.nodeType == 1){
        return anchor;
  }
}

Al leer otras respuestas y probarlo, parece que document.activeElementle dará el elemento que necesita en la mayoría de los navegadores.

Si tiene un navegador que no es compatible con document.activeElement si tiene jQuery, debería poder completarlo en todos los eventos de enfoque con algo muy simple como esto (no probado ya que no tengo un navegador que cumpla con esos criterios a mano ):

if (typeof document.activeElement === 'undefined') { // Check browser doesn't do it anyway
  $('*').live('focus', function () { // Attach to all focus events using .live()
    document.activeElement = this; // Set activeElement to the element that has been focussed
  });
}

Con dojo, puedes usar dijit.getFocus()

Solo pongo esto aquí para dar la solución que finalmente se me ocurrió.

Creé una propiedad llamada document.activeInputArea, y usé el complemento HotKeys de jQuery para atrapar los eventos del teclado para las teclas de flecha, tabular e ingresar, y creé un controlador de eventos para hacer clic en los elementos de entrada.

Luego ajusté activeInputArea cada vez que cambiaba el enfoque, para poder usar esa propiedad para averiguar dónde estaba.

Sin embargo, es fácil arruinar esto, porque si tiene un error en el sistema y el enfoque no está donde cree que está, entonces es muy difícil restaurar el enfoque correcto.

simple uso document.activeElement para encontrar el elemento activo actual