我试图根据具有焦点的当前元素将焦点移动到制表序列中的下一个元素。到目前为止,我的搜索中没有任何内容。
function OnFocusOut()
{
var currentElement = $get(currentElementId); // ID set by OnFocusIn
currentElementId = "";
currentElement.nextElementByTabIndex.focus();
}
当然nextElementByTabIndex是这个工作的关键部分。如何在标签序列中找到下一个元素?解决方案需要使用JScript而不是JQuery。
没有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;
}
}
}
我检查了上面的解决方案,发现它们非常冗长。只需一行代码即可完成:
<input>
要么
currentElement.nextElementSibling.focus();
这里currentElement可以是任何ie document.activeElement,如果当前元素在函数的上下文中,则为this。
我用keydown事件跟踪了tab和shift-tab事件
currentElement.previousElementSibling.focus();
一旦你有光标方向,那么你可以使用let cursorDirection = ''
$(document).keydown(function (e) {
let key = e.which || e.keyCode;
if (e.shiftKey) {
//does not matter if user has pressed tab key or not.
//If it matters for you then compare it with 9
cursorDirection = 'prev';
}
else if (key == 9) {
//if tab key is pressed then move next.
cursorDirection = 'next';
}
else {
cursorDirection == '';
}
});
或nextElementSibling.focus
方法
您是否为要循环的每个元素指定了自己的tabIndex值?如果是这样,你可以试试这个:
previousElementSibling.focus
你正在使用jquery,对吧?
希望这是有帮助的。
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
}
然后使用简单的JavaScript
<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)" />
这是一个关注下一个元素的更完整版本。它遵循规范指南,并使用tabindex对元素列表进行正确排序。如果要获取前一个元素,还会定义一个反向变量。
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;
}
}
}
}
这是对@Kano和@Mx提供的出色解决方案的潜在增强。如果要保留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]);
}
你可以这样称呼:
标签:
// Sort by explicit Tab Index, if any
var sort_by_TabIndex = function (elementA, elementB) {
let a = elementA.tabIndex || 1;
let b = elementB.tabIndex || 1;
if (a < b) { return -1; }
if (a > b) { return 1; }
return 0;
}
focussable.sort(sort_by_TabIndex);
Shift + Tab键:
$.tabNext();
$.tabPrev();
我修改<!DOCTYPE html>
<html>
<body>
<script src="https://code.jquery.com/jquery-3.3.1.js" integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=" crossorigin="anonymous"></script>
<script>
(function($){
'use strict';
/**
* Focusses the next :focusable element. Elements with tabindex=-1 are focusable, but not tabable.
* Does not take into account that the taborder might be different as the :tabbable elements order
* (which happens when using tabindexes which are greater than 0).
*/
$.focusNext = function(){
selectNextTabbableOrFocusable(':focusable');
};
/**
* Focusses the previous :focusable element. Elements with tabindex=-1 are focusable, but not tabable.
* Does not take into account that the taborder might be different as the :tabbable elements order
* (which happens when using tabindexes which are greater than 0).
*/
$.focusPrev = function(){
selectPrevTabbableOrFocusable(':focusable');
};
/**
* Focusses the next :tabable element.
* Does not take into account that the taborder might be different as the :tabbable elements order
* (which happens when using tabindexes which are greater than 0).
*/
$.tabNext = function(){
selectNextTabbableOrFocusable(':tabbable');
};
/**
* Focusses the previous :tabbable element
* Does not take into account that the taborder might be different as the :tabbable elements order
* (which happens when using tabindexes which are greater than 0).
*/
$.tabPrev = function(){
selectPrevTabbableOrFocusable(':tabbable');
};
function tabIndexToInt(tabIndex){
var tabIndexInded = parseInt(tabIndex);
if(isNaN(tabIndexInded)){
return 0;
}else{
return tabIndexInded;
}
}
function getTabIndexList(elements){
var list = [];
for(var i=0; i<elements.length; i++){
list.push(tabIndexToInt(elements.eq(i).attr("tabIndex")));
}
return list;
}
function selectNextTabbableOrFocusable(selector){
var selectables = $(selector);
var current = $(':focus');
// Find same TabIndex of remainder element
var currentIndex = selectables.index(current);
var currentTabIndex = tabIndexToInt(current.attr("tabIndex"));
for(var i=currentIndex+1; i<selectables.length; i++){
if(tabIndexToInt(selectables.eq(i).attr("tabIndex")) === currentTabIndex){
selectables.eq(i).focus();
return;
}
}
// Check is last TabIndex
var tabIndexList = getTabIndexList(selectables).sort(function(a, b){return a-b});
if(currentTabIndex === tabIndexList[tabIndexList.length-1]){
currentTabIndex = -1;// Starting from 0
}
// Find next TabIndex of all element
var nextTabIndex = tabIndexList.find(function(element){return currentTabIndex<element;});
for(var i=0; i<selectables.length; i++){
if(tabIndexToInt(selectables.eq(i).attr("tabIndex")) === nextTabIndex){
selectables.eq(i).focus();
return;
}
}
}
function selectPrevTabbableOrFocusable(selector){
var selectables = $(selector);
var current = $(':focus');
// Find same TabIndex of remainder element
var currentIndex = selectables.index(current);
var currentTabIndex = tabIndexToInt(current.attr("tabIndex"));
for(var i=currentIndex-1; 0<=i; i--){
if(tabIndexToInt(selectables.eq(i).attr("tabIndex")) === currentTabIndex){
selectables.eq(i).focus();
return;
}
}
// Check is last TabIndex
var tabIndexList = getTabIndexList(selectables).sort(function(a, b){return b-a});
if(currentTabIndex <= tabIndexList[tabIndexList.length-1]){
currentTabIndex = tabIndexList[0]+1;// Starting from max
}
// Find prev TabIndex of all element
var prevTabIndex = tabIndexList.find(function(element){return element<currentTabIndex;});
for(var i=selectables.length-1; 0<=i; i--){
if(tabIndexToInt(selectables.eq(i).attr("tabIndex")) === prevTabIndex){
selectables.eq(i).focus();
return;
}
}
}
/**
* :focusable and :tabbable, both taken from jQuery UI Core
*/
$.extend($.expr[ ':' ], {
data: $.expr.createPseudo ?
$.expr.createPseudo(function(dataName){
return function(elem){
return !!$.data(elem, dataName);
};
}) :
// support: jQuery <1.8
function(elem, i, match){
return !!$.data(elem, match[ 3 ]);
},
focusable: function(element){
return focusable(element, !isNaN($.attr(element, 'tabindex')));
},
tabbable: function(element){
var tabIndex = $.attr(element, 'tabindex'),
isTabIndexNaN = isNaN(tabIndex);
return ( isTabIndexNaN || tabIndex >= 0 ) && focusable(element, !isTabIndexNaN);
}
});
/**
* focussable function, taken from jQuery UI Core
* @param element
* @returns {*}
*/
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;
}
}
})(jQuery);
</script>
<a tabindex="5">5</a><br>
<a tabindex="20">20</a><br>
<a tabindex="3">3</a><br>
<a tabindex="7">7</a><br>
<a tabindex="20">20</a><br>
<a tabindex="0">0</a><br>
<script>
var timer;
function tab(){
window.clearTimeout(timer)
timer = window.setInterval(function(){$.tabNext();}, 1000);
}
function shiftTab(){
window.clearTimeout(timer)
timer = window.setInterval(function(){$.tabPrev();}, 1000);
}
</script>
<button tabindex="-1" onclick="tab()">Tab</button>
<button tabindex="-1" onclick="shiftTab()">Shift+Tab</button>
</body>
</html>
PlugIn来完成。
我从来没有实现过这个,但我已经研究过类似的问题了,这就是我想要的。
首先,我会看看你是否可以简单地使用fire a keypress
event作为当前具有焦点的元素上的Tab键。对于不同的浏览器,可能有不同的方法。
引用jQuery实现,您必须:
倾听Tab和Shift + Tab可能在网络上的其他地方都有很好的涵盖,所以我会跳过那一部分。
知道哪些元素是可制表的是棘手的。基本上,如果元素是可聚焦的并且没有设置tabindex="-1"
属性,则该元素是可制表的。那么我们必须要问哪些要素是可集中的。以下元素是可聚焦的:
input
,select
,textarea
,button
和object
元素未被禁用。a
和area
元素有href
或具有tabindex
集的数值。tabindex
集数值的元素。此外,只有在以下情况下才能聚焦元素:
display: none
。visibility
的计算值是visible
。这意味着具有visibility
集的最近祖先必须具有visible
的值。如果没有祖先设置visibility
,则计算值为visible
。更多细节在另一个Stack Overflow answer。
文档中元素的Tab键顺序由tabindex
属性控制。如果没有设置值,则tabindex
实际上是0
。
该文件的tabindex
订单是:1,2,3,...,0。
最初,当body
元素(或没有元素)具有焦点时,Tab键顺序中的第一个元素是最低的非零tabindex
。如果多个元素具有相同的tabindex
,则按文档顺序进行,直到使用该tabindex
到达最后一个元素。然后你移动到下一个最低的tabindex
并继续进行。最后,使用零(或空)tabindex
完成这些元素。
这是我为此目的建立的东西:
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();
}
}
}
我创造了一个simple jQuery plugin就是这样做的。它使用jQuery UI的':tabbable'选择器来查找下一个'tabbable'元素并选择它。
用法示例:
// Simulate tab key when element is clicked
$('.myElement').bind('click', function(event){
$.tabNext();
return false;
});
答案的核心在于找到下一个元素:
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
的优先级。
正如上面的评论所述,我认为任何浏览器都不会公开Tab键顺序信息。这里简化了浏览器以Tab键顺序获取下一个元素的操作:
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
。
然后你只需要知道制表位的规则:
tabIndex="1"
具有次优先级。tabIndex="2"
是下一个,依此类推。tabIndex="3"
(默认为tabbable)具有最低优先级。tabIndex="0"
(默认情况下不是tabbable)不作为制表位。下面是一个如何使用纯Javascript按顺序构建制表位列表的示例:
tabIndex="-1"
我们首先走DOM,按索引顺序收集所有制表位。然后我们组装最终列表。请注意,我们在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]);
}
为1,2,3等的项目之后,在列表的最后添加tabIndex="0"
的项目。
有关完整工作示例,您可以使用“输入”键进行选项卡,请查看此tabIndex
。
这是我关于SO的第一篇文章,所以我没有足够的声誉来评论接受的答案,但我必须将代码修改为以下内容:
contenteditable
将var更改为常量是非关键的。主要的变化是我们摆脱了检查tabindex!=“ - ”的选择器。然后,如果元素具有属性tabindex并且它设置为“-1”,我们不认为它是可聚焦的。
我需要更改这个的原因是因为当将tabindex =“ - 1”添加到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()
}
}
}
时,该元素仍然被认为是可聚焦的,因为它匹配“input [type = text]:not([disabled])”选择器。我的更改等同于“如果我们是非禁用文本输入,并且我们有tabIndex属性,并且该属性的值为-1,那么我们不应该被认为是可聚焦的。
我相信,当接受的答案的作者编辑了他们对tabIndex属性进行说明的答案时,他们没有正确地这样做。如果不是这样,请告诉我