Фокус Следующий Элемент В Индексе Вкладки
Я пытаюсь переместить фокус на следующий элемент в последовательности вкладок на основе текущего элемента, который имеет фокус. До сих пор я ничего не нашел в своих поисках.
function OnFocusOut()
{
var currentElement = $get(currentElementId); // ID set by OnFocusIn
currentElementId = "";
currentElement.nextElementByTabIndex.focus();
}
конечно nextElementByTabIndex является ключевой частью для этой работы. Как найти следующий элемент в последовательности вкладок? Решение должно быть основано на использовании JScript, а не что-то вроде JQuery.
12 ответов:
без jquery: Прежде всего, на ваших закладочных элементах добавьте
class="tabable"Это позволит нам выбрать их позже. (Не забывайте о"."префикс селектора класса в коде ниже)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; } } }
я никогда не реализовывал это, но я изучил подобную проблему, и вот что я хотел бы попробовать.
попробуй сначала
во-первых, я хотел бы посмотреть, если бы вы могли просто огонь a
keypressсобытие для клавиши Tab на элементе, который в настоящее время имеет фокус. Там может быть другой способ сделать это для разных браузеров.если это не сработает, вам придется работать усерднее...
ссылаясь на реализацию jQuery, вы обязательно:
- слушайте Tab и Shift + Tab
- знать, какие элементы табуляции
- понять, как работает порядок вкладок
1. Слушайте Tab и Shift + Tab
прослушивание Tab и Shift + Tab, вероятно, хорошо освещены в другом месте в интернете, поэтому я пропущу эту часть.
2. Знайте, какие элементы табулируются
знание того, какие элементы являются вкладками, сложнее. В принципе, элемент является вкладка-возможность, если она фокусируется и не имеет атрибута
tabindex="-1"set. Итак, мы должны спросить, какие элементы являются фокусируемыми. Следующие элементы являются фокусируемыми:
input,select,textarea,buttonиobjectэлементы, которые не отключаются.aиareaэлементы, которые имеютhrefили иметь числовое значениеtabindexset.- любой элемент, который имеет числовое значение
tabindexнабор.кроме того, элемент фокусируется только в том случае, если:
- ни один из его предков
display: none.- вычисленное значение
visibilityиvisible. Это означает, что ближайший предок должен иметьvisibilityset должен иметь значениеvisible. Если ни один предок не имеетvisibilityустановить, то вычисленное значениеvisible.подробнее в другом ответ переполнения стека.
3. Поймите, как работает порядок вкладок
порядок табуляции элементов в документе контролируется . Если значение не установлено,
tabindexэффективно0.The
tabindexзаказ на документ есть: 1, 2, 3, ..., 0.изначально, когда
bodyэлемент (или нет элемента) имеет фокус, первый элемент в порядке табуляции является самым низким ненулевымtabindex. Если несколько элементов имеют то же самоеtabindex, затем вы идете в порядке документа пока вы не достигнете последнего элемента с этимtabindex. Затем вы переходите к следующему самому низкомуtabindexи процесс продолжается. Наконец, закончите с этими элементами с нулем (или пустым)tabindex.
Я создал простой плагин jQuery что делает именно это. Он использует ':селектор tabbable' пользовательского интерфейса jQuery, чтобы найти следующий tabbable элемент и выбрать его.
пример использования:
// Simulate tab key when element is clicked $('.myElement').bind('click', function(event){ $.tabNext(); return false; });
вот что я строю для этой цели:
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(); } } }характеристики:
- настраиваемый набор фокусируемых элементов
- jQuery не требуется
- работает во всех современных браузерах
- быстрый и легкий
суть ответа заключается в поиске следующего элемента:
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]; }использование:
var nextEl = findNextTabStop(element); nextEl.focus();обратите внимание, что я не забочусь о приоритизации
tabIndex.
Как упоминалось в комментарии выше, я не думаю, что какие-либо браузеры предоставляют информацию о порядке табуляции. Здесь упрощенное приближение того, что браузер делает, чтобы получить следующий элемент в порядке табуляции:
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();это только рассматривает некоторые теги и игнорирует
кажется, что вы можете проверить
tabIndexсвойство элемента, чтобы определить, является ли он фокусируемым. Элемент, который не является фокусируемым, имеетtabindexиз "-1".тогда вам просто нужно знать правила для табуляции:
tabIndex="1"имеет самый высокий приоритет.tabIndex="2"имеет следующий наивысший приоритет.tabIndex="3"следующий, и так далее.tabIndex="0"(или tabbable по умолчанию) имеет самый низкий приоритет.tabIndex="-1"(или не табулируется по умолчанию)не действует как табуляция.- для двух элементов, имеющих одинаковый tabIndex, тот, который появляется первым в DOM, имеет более высокий приоритет.
вот пример того, как построить список табуляторов, в последовательности, используя чистый Javascript:
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]); }мы сначала идем по DOM, собирая все табуляции в последовательности с их индексом. Затем мы собираем окончательный список. Заметить это мы добавляем элементы с
tabIndex="0"в самом конце списка, после пользования сtabIndexна 1, 2, 3, и т. д.для полностью рабочего примера, где вы можете использовать вкладку с помощью клавиши "enter", проверьте это скрипка.
вы указали свои собственные значения tabIndex для каждого элемента, который вы хотите прокрутить? если да, то вы можете попробовать это:
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 }вы используете jquery, верно?
надеюсь, что это полезно.
<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)" />тогда используйте простой javascript
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; } } } }
Tabbable это небольшой пакет JS, который дает вам список всех элементов табуляции в разделе Заказ. Таким образом, вы можете найти свой элемент в этом списке, а затем сосредоточиться на следующей записи списка.
пакет правильно обрабатывает сложные крайние случаи, упомянутые в других ответах (например, ни один предок не может быть
display: none). И это не зависит от jQuery!на момент написания этой статьи (версия 1.1.1), он имеет предостережения, что он не поддерживает IE8, и что Ошибки браузера не позволяют ему обрабатывать
contenteditableправильно.
Это мой первый пост на SO, поэтому у меня недостаточно репутации, чтобы прокомментировать принятый ответ, но мне пришлось изменить код следующим образом:
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() } } }изменение var на константу не является критическим. Главное изменение заключается в том, что мы избавляемся от селектора, который проверяет tabindex != "-1". Затем позже, если элемент имеет атрибут tabindex и он установлен в "-1", мы не считаем его фокусируемым.
причина, по которой мне нужно было изменить это было потому, что при добавлении tabindex= " -1 " к
<input>, этот элемент по-прежнему считался фокусируемым, поскольку он соответствует селектору "input[type=text]:not([disabled])". Мое изменение эквивалентно "если мы не отключаем ввод текста, и у нас есть атрибут tabIndex, а значение этого атрибута равно -1, то мы не должны считаться фокусируемыми.Я считаю, что когда автор принятого ответа отредактировал свой ответ для учета атрибута tabIndex, они не сделали этого правильно. Пожалуйста я знаю, если это не так
вот более полная версия фокусировки на следующем элементе. Он соответствует требованиям спецификации и сортировка списка элементов, правильно используя свойство tabindex. Также обратная переменная определяется, если вы хотите получить предыдущий элемент.
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]); }
Comments