2011-10-05 23 views
23

This answer indica qué elementos HTML pueden recibir el foco. ¿Hay un selector jQuery que coincida exactamente con estos elementos?¿Hay un selector jQuery para obtener todos los elementos que pueden enfocar?

Por ahora solo estoy usando $('input,select,textarea,a'), pero me pregunto si hay algo más preciso.

+0

Probablemente no. Tal vez pruebe el selector [': input'] (http://api.jquery.com/input-selector/)? – Bojangles

+0

¿Qué estás tratando de hacer una vez que tienes la lista de elementos enfocables? – Dennis

+0

@Dennis: desplácese hacia abajo para asegurarse de que estén visibles cuando estén enfocados. http://stackoverflow.com/questions/7650892/how-to-scroll-down-the-page-when-a-covered-input-box-is-focused – ripper234

Respuesta

5

Se puede comprobar si hay elementos que tienen la función focus():

$('*').each(function() { 
    if(typeof this.focus == 'function') { 
    // Do something with this element 
    } 
}) ; 

Editar Pensando un poco más, probablemente tiene sentido tener *:visible en lugar de sólo * como selector para la mayoría de aplicaciones de esta.

+0

Definitivamente el camino a seguir. No creo que sea posible en lo que respecta a los selectores explícitos, ya que los selectores de jQuery están basados ​​en http://sizzlejs.com. – ifightcrime

+0

excepto que, si lee la publicación vinculada en el PO, dice: 'los únicos elementos que tienen un método focus() son HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement y HTMLAnchorElement. Esto omite en particular HTMLButtonElement y HTMLAreaElement. Por lo tanto, la prueba de '.focus()' no lo hará (aparentemente). – Lee

+0

Los elementos DOM son objetos host, no necesitan ajustarse a las reglas de ECMAScript y, por lo tanto, su respuesta al operador * typeof * puede ser cualquier cosa, incluido arrojar un error. En IE 8, 'typeof element.focus' devuelve * object * en una entrada de texto, por lo que la prueba anterior fallará en aproximadamente 1: 5 navegadores en uso, posiblemente más. – RobG

28

Desde el other SO answer referred to by the OP:

navegadores de hoy definen el enfoque() en HTMLElement, ...

lo tanto, esto significa que las pruebas de focus como miembro del elemento es no efectiva , porque todos los elementos lo tendrán, independientemente de si realmente aceptan el enfoque o no.

... sino un elemento no va a tomar realmente el foco a menos que sea uno de:

  • HTMLAnchorElement/HTMLAreaElement con un href * HTMLInputElement/HTMLSelectElement/HTMLTextAreaElement/HTMLButtonElement pero no con disabled (IE realmente le da un error si lo intenta), y las cargas de archivos tienen un comportamiento inusual por razones de seguridad
  • HTMLIFrameElement (aunque centrarse no hace nada útil). Otros elementos de inclusión también, tal vez, no los he probado todos.
  • Cualquier elemento con un tabindex

Así que, ¿qué pasa con nombrar a todos aquellos explícitamente en una jQuery Selector?

$('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]') 

Actualización # 1:

I updated your jsFiddle here. Parece que funciona

También agregué elementos con el atributo contenteditable a la lista anterior.


Actualización # 2:

Como @ jfriend00 señaló: "Dependiendo del uso, se puede querer filtrar los elementos que no son visibles". Para lograr esto, simplemente aplique .filter(':visible') al conjunto generado a partir del selector anterior.


Actualización # 3:

Como Xavin pointed out: jQuery UI tiene ahora un selector, :focusable, que realiza esta función. Si ya está utilizando la interfaz de usuario de jQuery, este podría ser el camino a seguir. Si no es así, entonces es posible que desee check out how jQuery UI does it. En cualquier caso, la descripción en la página de jQuery UI para :focusable es útil:

Elementos del siguiente tipo son enfocable si no se desactivan: de entrada, seleccionar, área de texto, botón, y el objeto. Los anclajes son enfocables si tienen un atributo href o tabindex. los elementos de área son enfocables si están dentro de un mapa con nombre, tienen un atributo href y hay una imagen visible usando el mapa. Todos los otros elementos son enfocables basados ​​únicamente en su atributo tabindex y visibilidad.

Por lo tanto, el selector he propuesto más arriba está cerca, pero no tiene en cuenta algunos matices.

Aquí está la función arrancada de jQuery UI, con pequeñas adaptaciones para que sea autónoma. (Las adaptaciones no se han probado, pero debería funcionar):

function focusable(element) { 
    var map, mapName, img, 
     nodeName = element.nodeName.toLowerCase(), 
     isTabIndexNotNaN = !isNaN($.attr(element, "tabindex")); 
    if ("area" === nodeName) { 
     map = element.parentNode; 
     mapName = map.name; 
     if (!element.href || !mapName || map.nodeName.toLowerCase() !== "map") { 
      return false; 
     } 
     img = $("img[usemap=#" + mapName + "]")[0]; 
     return !!img && visible(img); 
    } 
    return (/input|select|textarea|button|object/.test(nodeName) ? 
     !element.disabled : 
     "a" === nodeName ? 
      element.href || isTabIndexNotNaN : 
      isTabIndexNotNaN) && 
     // the element and all of its ancestors must be visible 
     visible(element); 

    function visible(element) { 
     return $.expr.filters.visible(element) && 
     !$(element).parents().addBack().filter(function() { 
      return $.css(this, "visibility") === "hidden"; 
     }).length; 
    } 
} 

Nota: la función de arriba todavía depende de jQuery, pero no debería requerir jQuery UI.

+0

Según el uso, es posible que desee filtrar los elementos que no son visibles. – jfriend00

+0

Quizás no haya una mejor manera, pero el problema con este tipo de código es que es frágil. Tendrá que mantenerse cada vez que haya un nuevo tipo de elemento editable o un nuevo atributo que haga que algo se pueda editar. – jfriend00

+0

@ jfriend00 - buen punto. Actualicé mi respuesta para incluir su sugerencia. – Lee

0

En lugar de obtener una lista de elementos enfocables, puede intentar configurar un controlador de enfoque en el elemento body que captura los eventos de foco.

$(document.body).on("focus", "*", function(e) { 
    //Scroll to e.target 
}); 
+4

Excepto que hemos comprobado que no funciona el tipo de 'this.focus'. – jfriend00

4

Otro selector simple, pero completo, jQuery podría ser ésta:

$('a[href], area[href], input, select, textarea, button, iframe, object, embed, *[tabindex], *[contenteditable]') 
.not('[tabindex=-1], [disabled], :hidden') 
+1

el '*' delante de '[tabindex]' es innecesario – Omu

+0

Sí, ¡tienes razón! – tzi

0

tengo una solución relativamente simple que devuelve todos los niños tabbable, en su orden de tabulación, sin usar jQuery.

function tabbable(el) { 
    return [].map.call(el.querySelectorAll([ 
     'input', 
     'select', 
     'a[href]', 
     'textarea', 
     'button', 
     '[tabindex]' 
    ]), function(el, i) { return { el, i } }). 
     filter(function(e) { 
      return e.el.tabIndex >= 0 && !e.el.disabled && e.el.offsetParent; }). 
     sort(function(a,b) { 
      return a.el.tabIndex === b.el.tabIndex ? a.i - b.i : (a.el.tabIndex || 9E9) - (b.el.tabIndex || 9E9); }); 
} 

Para IE, considere implementar una verificación de visibilidad diferente a e.el.offsetParent. jQuery puede ayudarte aquí.

Si no necesita los elementos ordenados, omita la llamada al sort().

Cuestiones relacionadas