javascript jscript.net

javascript - Enfocar el siguiente elemento en el índice de pestañas



jscript.net (12)

Estoy intentando mover el foco al siguiente elemento en la secuencia de pestañas según el elemento actual que tiene foco. Hasta ahora no he encontrado nada en mis búsquedas.

function OnFocusOut() { var currentElement = $get(currentElementId); // ID set by OnFocusIn currentElementId = ""; currentElement.nextElementByTabIndex.focus(); }

Por supuesto, el nextElementByTabIndex es la parte clave para que esto funcione. ¿Cómo encuentro el siguiente elemento en la secuencia de pestañas? La solución debería estar basada en JScript y no en algo como JQuery.


¿Especificó sus propios valores de tabIndex para cada elemento por el que desea pasar? si es así, puedes intentar esto:

var lasTabIndex = 10; //Set this to the highest tabIndex you have function OnFocusOut() { var currentElement = $get(currentElementId); // ID set by OnFocusIn var curIndex = $(currentElement).attr(''tabindex''); //get the tab index of the current element if(curIndex == lastTabIndex) { //if we are on the last tabindex, go back to the beginning curIndex = 0; } $(''[tabindex='' + (curIndex + 1) + '']'').focus(); //set focus on the element that has a tab index one greater than the current tab index }

Estás usando jquery, ¿verdad?


Aquí hay algo que construyo para este propósito:

focusNextElement: function () { //add all elements we want to include in our selection var focussableElements = ''a:not([disabled]), button:not([disabled]), input[type=text]:not([disabled]), [tabindex]:not([disabled]):not([tabindex="-1"])''; if (document.activeElement && document.activeElement.form) { var focussable = Array.prototype.filter.call(document.activeElement.form.querySelectorAll(focussableElements), function (element) { //check for visibility while always include the current activeElement return element.offsetWidth > 0 || element.offsetHeight > 0 || element === document.activeElement }); var index = focussable.indexOf(document.activeElement); if(index > -1) { var nextElement = focussable[index + 1] || focussable[0]; nextElement.focus(); } } }

caracteristicas:

  • conjunto configurable de elementos enfocables
  • no se necesita jQuery
  • funciona en todos los navegadores modernos
  • rápido y ligero

Aquí hay una versión más completa de enfocarse en el siguiente elemento. Sigue las pautas de la especificación y ordena la lista de elementos correctamente mediante el uso de tabindex. También se define una variable inversa si desea obtener el elemento anterior.

function focusNextElement( reverse, activeElem ) { /*check if an element is defined or use activeElement*/ activeElem = activeElem instanceof HTMLElement ? activeElem : document.activeElement; let queryString = [ ''a:not([disabled]):not([tabindex="-1"])'', ''button:not([disabled]):not([tabindex="-1"])'', ''input:not([disabled]):not([tabindex="-1"])'', ''select:not([disabled]):not([tabindex="-1"])'', ''[tabindex]:not([disabled]):not([tabindex="-1"])'' /* add custom queries here */ ].join('',''), queryResult = Array.prototype.filter.call(document.querySelectorAll(queryString), elem => { /*check for visibility while always include the current activeElement*/ return elem.offsetWidth > 0 || elem.offsetHeight > 0 || elem === activeElem; }), indexedList = queryResult.slice().filter(elem => { /* filter out all indexes not greater than 0 */ return elem.tabIndex == 0 || elem.tabIndex == -1 ? false : true; }).sort((a, b) => { /* sort the array by index from smallest to largest */ return a.tabIndex != 0 && b.tabIndex != 0 ? (a.tabIndex < b.tabIndex ? -1 : b.tabIndex < a.tabIndex ? 1 : 0) : a.tabIndex != 0 ? -1 : b.tabIndex != 0 ? 1 : 0; }), focusable = [].concat(indexedList, queryResult.filter(elem => { /* filter out all indexes above 0 */ return elem.tabIndex == 0 || elem.tabIndex == -1 ? true : false; })); /* if reverse is true return the previous focusable element if reverse is false return the next focusable element */ return reverse ? (focusable[focusable.indexOf(activeElem) - 1] || focusable[focusable.length - 1]) : (focusable[focusable.indexOf(activeElem) + 1] || focusable[0]); }


Como mencioné en un comentario anterior, no creo que ningún navegador expone información sobre el orden de las pestañas. Aquí una aproximación simplificada de lo que hace el navegador para obtener el siguiente elemento en orden de tabulación:

var allowedTags = {input: true, textarea: true, button: true}; var walker = document.createTreeWalker( document.body, NodeFilter.SHOW_ELEMENT, { acceptNode: function(node) { if (node.localName in allowedTags) return NodeFilter.FILTER_ACCEPT; else NodeFilter.FILTER_SKIP; } }, false ); walker.currentNode = currentElement; if (!walker.nextNode()) { // Restart search from the start of the document walker.currentNode = walker.root; walker.nextNode(); } if (walker.currentNode && walker.currentNode != walker.root) walker.currentNode.focus();

Esto solo considera algunas etiquetas e ignora el atributo tabindex pero podría ser suficiente dependiendo de lo que esté tratando de lograr.


El núcleo de la respuesta está en encontrar el siguiente elemento:

function findNextTabStop(el) { var universe = document.querySelectorAll(''input, button, select, textarea, a[href]''); var list = Array.prototype.filter.call(universe, function(item) {return item.tabIndex >= "0"}); var index = list.indexOf(el); return list[index + 1] || list[0]; }

Uso:

var nextEl = findNextTabStop(element); nextEl.focus();

Tenga en cuenta que no me importa priorizar tabIndex .


Espero que esto sea útil.

<input size="2" tabindex="1" id="one" maxlength="2" onkeyup="toUnicode(this)" /> <input size="2" tabindex="2" id="two" maxlength="2" onkeyup="toUnicode(this)" /> <input size="2" tabindex="3" id="three" maxlength="2" onkeyup="toUnicode(this)" />

luego usa javascript simple

function toUnicode(elmnt) { var next; if (elmnt.value.length==elmnt.maxLength) { next=elmnt.tabIndex + 1; //look for the fields with the next tabIndex var f = elmnt.form; for (var i = 0; i < f.elements.length; i++) { if (next<=f.elements[i].tabIndex) { f.elements[i].focus(); break; } } } }


Esta es mi primera publicación en SO, por lo que no tengo la reputación suficiente para comentar la respuesta aceptada, pero tuve que modificar el código a lo siguiente:

export function focusNextElement () { //add all elements we want to include in our selection const focussableElements = ''a:not([disabled]), button:not([disabled]), input[type=text]:not([disabled])'' if (document.activeElement && document.activeElement.form) { var focussable = Array.prototype.filter.call( document.activeElement.form.querySelectorAll(focussableElements), function (element) { // if element has tabindex = -1, it is not focussable if ( element.hasAttribute(''tabindex'') && element.tabIndex === -1 ){ return false } //check for visibility while always include the current activeElement return (element.offsetWidth > 0 || element.offsetHeight > 0 || element === document.activeElement) }); console.log(focussable) var index = focussable.indexOf(document.activeElement); if(index > -1) { var nextElement = focussable[index + 1] || focussable[0]; console.log(nextElement) nextElement.focus() } } }

El cambio de var a constante no es crítico. El principal cambio es que nos deshacemos del selector que comprueba tabindex! = "-1". Luego, más adelante, si el elemento tiene el atributo tabindex Y está establecido en "-1", NO lo consideramos enfocable.

La razón por la que necesitaba cambiar esto era porque al agregar tabindex = "- 1" a una <input> , este elemento todavía se consideraba enfocable porque coincide con el selector "input [type = text]: not ([disabled])". Mi cambio es equivalente a "si tenemos una entrada de texto no desactivada, y tenemos un atributo tabIndex, y el valor de ese atributo es -1, entonces no deberíamos considerarlo enfocable.

Creo que cuando el autor de la respuesta aceptada editó su respuesta para dar cuenta del atributo tabIndex, no lo hicieron correctamente. Por favor, avíseme si este no es el caso


Nunca lo he implementado, pero he investigado un problema similar, y esto es lo que probaría.

Prueba esto primero

Primero, vería si pudiera disparar un evento de keypress para la tecla Tab en el elemento que actualmente tiene foco. Puede haber una forma diferente de hacer esto para diferentes navegadores.

Si eso no funciona, tendrás que trabajar más duro ...

Al hacer referencia a la implementación de jQuery, debes hacer lo siguiente:

  1. Escuche Tab y Mayús + Tabulador
  2. Sepa qué elementos son tabulables
  3. Comprender cómo funciona el orden de tabulación

1. Escuche Tab y Mayús + Tabulador

La escucha de Tab, Shift + Tab probablemente esté bien cubierta en otra parte de la web, así que omitiré esa parte.

2. Sepa qué elementos son tab-able

Saber qué elementos son tabulables es más complicado. Básicamente, un elemento puede tabindex="-1" si es enfocable y no tiene el atributo tabindex="-1" establecido. Entonces, debemos preguntarnos qué elementos son enfocables. Los siguientes elementos son enfocables:

  • input , select , textarea , button y object elements que no están deshabilitados.
  • y elementos de area que tienen un href o tienen un valor numérico para el conjunto tabindex .
  • cualquier elemento que tenga un valor numérico para el conjunto tabindex .

Además, un elemento es enfocable solo si:

  • Ninguno de sus antepasados ​​tiene display: none .
  • El valor calculado de visibility es visible . Esto significa que el antecesor más cercano para tener el conjunto de visibility debe tener un valor de visible . Si ningún antepasado tiene visibility establecida, entonces el valor calculado es visible .

Más detalles están en otra respuesta de desbordamiento de pila .

3. Comprender cómo funciona el orden de tabulación

El orden de tabulación de los elementos en un documento está controlado por el atributo tabindex . Si no se establece ningún valor, el tabindex es efectivamente 0 .

El orden tabindex para el documento es: 1, 2, 3, ..., 0.

Inicialmente, cuando el elemento del body (o ningún elemento) tiene foco, el primer elemento en el orden de tabulación es el tabindex no nulo más tabindex . Si los elementos múltiples tienen el mismo tabindex , vaya en orden de documento hasta que llegue al último elemento con ese tabindex . Luego pasas al siguiente tabindex más tabindex y el proceso continúa. Finalmente, termine con esos elementos con un tabindex cero (o vacío).


Parece que puede verificar la propiedad tabIndex de un elemento para determinar si es enfocable. Un elemento que no es tabindex tiene un tabindex de "-1".

Entonces solo necesita saber las reglas para las tabulaciones:

  • tabIndex="1" tiene la prioridad más alta.
  • tabIndex="2" tiene la siguiente prioridad más alta.
  • tabIndex="3" es el siguiente, y así sucesivamente.
  • tabIndex="0" (o tabbable por defecto) tiene la prioridad más baja.
  • tabIndex="-1" (o no tabbable de forma predeterminada) no actúa como una tabulación.
  • Para dos elementos que tienen el mismo tabIndex, el que aparece primero en el DOM tiene la prioridad más alta.

Aquí hay un ejemplo de cómo crear la lista de tabulaciones, en secuencia, usando Javascript puro:

function getTabStops(o, a, el) { // Check if this element is a tab stop if (el.tabIndex > 0) { if (o[el.tabIndex]) { o[el.tabIndex].push(el); } else { o[el.tabIndex] = [el]; } } else if (el.tabIndex === 0) { // Tab index "0" comes last so we accumulate it seperately a.push(el); } // Check if children are tab stops for (var i = 0, l = el.children.length; i < l; i++) { getTabStops(o, a, el.children[i]); } } var o = [], a = [], stops = [], active = document.activeElement; getTabStops(o, a, document.body); // Use simple loops for maximum browser support for (var i = 0, l = o.length; i < l; i++) { if (o[i]) { for (var j = 0, m = o[i].length; j < m; j++) { stops.push(o[i][j]); } } } for (var i = 0, l = a.length; i < l; i++) { stops.push(a[i]); }

Primero recorremos el DOM y recopilamos todas las tabulaciones en secuencia con su índice. Luego armamos la lista final. Tenga en cuenta que agregamos los elementos con tabIndex="0" al final de la lista, después de los elementos con un tabIndex de 1, 2, 3, etc.

Para un ejemplo totalmente funcional, donde puede buscar con la tecla "enter", revise este fiddle .


Sin jquery: Antes que nada, en sus elementos tab-able, agregue class="tabable" esto nos permitirá seleccionarlos más tarde.

var lastTabIndex = 10; function OnFocusOut() { var currentElement = $get(currentElementId); // ID set by OnFOcusIn var curIndex = currentElement.tabIndex; //get current elements tab index if(curIndex == lastTabIndex) { //if we are on the last tabindex, go back to the beginning curIndex = 0; } var tabbables = document.querySelectorAll("tabable"); //get all tabable elements for(var i=0; i<tabbables.length; i++) { //loop through each element if(tabbables[i].tabIndex == (curIndex+1)) { //check the tabindex to see if it''s the element we want tabbables[i].focus(); //if it''s the one we want, focus it and exit the loop break; } } }


Tabbable es un pequeño paquete JS que le proporciona una lista de todos los elementos tabulables en orden de tabulación . Así que podrías encontrar tu elemento dentro de esa lista, luego enfocarte en la siguiente entrada de la lista.

El paquete maneja correctamente los casos extremos complicados mencionados en otras respuestas (p. Ej., No se puede display: none ningún ancestro display: none ). ¡Y no depende de jQuery!

A partir de este escrito (versión 1.1.1), tiene la advertencia de que no es compatible con IE8, y que los errores del navegador impiden que se maneje correctamente.


Creé un plugin jQuery simple que hace justamente esto. Utiliza el selector '': tabbable'' de jQuery UI para encontrar el siguiente elemento ''tabbable'' y lo selecciona.

Ejemplo de uso:

// Simulate tab key when element is clicked $(''.myElement'').bind(''click'', function(event){ $.tabNext(); return false; });