Javascript 聚焦标签索引中的下一个元素
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7208161/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Focus Next Element In Tab Index
提问by JadziaMD
I am trying to move the focus to the next element in the tab sequence based upon the current element which has focus. Thus far I have not turned up anything in my searches.
我试图根据当前具有焦点的元素将焦点移到选项卡序列中的下一个元素。到目前为止,我还没有在我的搜索中找到任何东西。
function OnFocusOut()
{
var currentElement = $get(currentElementId); // ID set by OnFocusIn
currentElementId = "";
currentElement.nextElementByTabIndex.focus();
}
Of course the nextElementByTabIndex is the key part for this to work. How do I find the next element in the tab sequence? The solution would need to be based using JScript and not something like JQuery.
当然 nextElementByTabIndex 是这个工作的关键部分。如何在选项卡序列中找到下一个元素?该解决方案需要基于使用 JScript 而不是类似 JQuery 的东西。
采纳答案by Brian Glaz
Without jquery:
First of all, on your tab-able elements, add class="tabable"
this will let us select them later.
(Do not forget the "." class selector prefix in the code below)
没有 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;
}
}
}
回答by Chris Calo
I've never implemented this, but I've looked into a similar problem, and here's what I would try.
我从来没有实现过这个,但我已经研究过类似的问题,这就是我会尝试的。
Try this first
先试试这个
First, I would see if you could simply fire a keypress
eventfor the Tab key on the element that currently has focus. There may be a different way of doing this for different browsers.
首先,我会看看您是否可以简单地为当前具有焦点的元素上的 Tab 键触发一个keypress
事件。对于不同的浏览器,可能有不同的方法来执行此操作。
If that doesn't work, you'll have to work harder…
如果这不起作用,你将不得不更加努力......
Referencing the jQuery implementation, you must:
引用 jQuery 实现,您必须:
- Listen for Tab and Shift+Tab
- Know which elements are tab-able
- Understand how tab order works
- 听 Tab 和 Shift+Tab
- 知道哪些元素可以制表
- 了解 Tab 键顺序的工作原理
1. Listen for Tab and Shift+Tab
1. 听 Tab 和 Shift+Tab
Listening for Tab and Shift+Tab are probably well-covered elsewhere on the web, so I'll skip that part.
听 Tab 和 Shift+Tab 可能在网络上的其他地方都有很好的介绍,所以我会跳过那部分。
2. Know which elements are tab-able
2. 知道哪些元素是可制表的
Knowing which elements are tab-able is trickier. Basically, an element is tab-able if it is focusable and does not have the attribute tabindex="-1"
set. So then we must ask which elements are focusable. The following elements are focusable:
知道哪些元素可以制表是比较棘手的。基本上,如果一个元素是可聚焦的并且没有tabindex="-1"
设置属性,则它是可选项卡的。那么我们必须询问哪些元素是可聚焦的。以下元素是可聚焦的:
input
,select
,textarea
,button
, andobject
elements that aren't disabled.a
andarea
elements that have anhref
or have a numerical value fortabindex
set.- any element that has a numerical value for
tabindex
set.
input
、select
、textarea
、button
和object
未禁用的元素。a
和area
具有href
或具有tabindex
集合数值的元素。- 任何具有
tabindex
集合数值的元素。
Furthermore, an element is focusable only if:
此外,一个元素只有在以下情况下才是可聚焦的:
- None of its ancestors are
display: none
. - The computed value of
visibility
isvisible
. This means that the nearest ancestor to havevisibility
set must have a value ofvisible
. If no ancestor hasvisibility
set, then the computed value isvisible
.
- 它的祖先都不是
display: none
。 - 的计算值
visibility
是visible
。这意味着要visibility
设置的最近祖先的值必须为visible
。如果没有visibility
设置祖先,则计算值为visible
。
More details are in another Stack Overflow answer.
更多细节在另一个Stack Overflow 答案中。
3. Understand how tab order works
3. 了解 Tab 键顺序的工作原理
The tab order of elements in a document is controlled by the tabindex
attribute. If no value is set, the tabindex
is effectively 0
.
文档中元素的 Tab 键顺序由tabindex
属性控制。如果未设置任何值,tabindex
则有效0
。
The tabindex
order for the document is: 1, 2, 3, …, 0.
tabindex
文档的顺序是:1, 2, 3, ..., 0。
Initially, when the body
element (or no element) has focus, the first element in the tab order is the lowest non-zero tabindex
. If multiple elements have the same tabindex
, you then go in document order until you reach the last element with that tabindex
. Then you move to the next lowest tabindex
and the process continues. Finally, finish with those elements with a zero (or empty) tabindex
.
最初,当body
元素(或没有元素)具有焦点时,Tab 键顺序中的第一个元素是最低的非零元素tabindex
。如果多个元素具有相同的元素tabindex
,则按文档顺序进行,直到到达具有该元素的最后一个元素tabindex
。然后你移动到下一个最低点tabindex
,这个过程继续。最后,用零(或空)完成这些元素tabindex
。
回答by Mx.
Here's something I build for this purpose:
这是我为此目的构建的东西:
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();
}
}
}
Features:
特征:
- configurable set of focusable elements
- no jQuery needed
- works in all modern browsers
- fast & lightweight
- 可配置的可聚焦元素集
- 不需要jQuery
- 适用于所有现代浏览器
- 快速轻便
回答by Mark Lagendijk
I created a simple jQuery pluginwhich does just this. It uses the ':tabbable' selector of jQuery UI to find the next 'tabbable' element and selects it.
我创建了一个简单的 jQuery 插件,它就是这样做的。它使用 jQuery UI 的 ':tabbable' 选择器来查找下一个 'tabbable' 元素并选择它。
Example usage:
用法示例:
// Simulate tab key when element is clicked
$('.myElement').bind('click', function(event){
$.tabNext();
return false;
});
回答by André Werlang
The core of the answer lies on finding the next element:
答案的核心在于找到下一个元素:
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];
}
Usage:
用法:
var nextEl = findNextTabStop(element);
nextEl.focus();
Notice I don't care about prioritizing tabIndex
.
请注意,我不关心优先级tabIndex
。
回答by chowey
It seems that you can check the tabIndex
property of an element to determine if it is focusable. An element that is not focusable has a tabindex
of "-1".
似乎您可以检查tabIndex
元素的属性以确定它是否可聚焦。不可聚焦的元素具有tabindex
“-1”。
Then you just need to know the rules for tab stops:
然后你只需要知道制表位的规则:
tabIndex="1"
has the highest priorty.tabIndex="2"
has the next highest priority.tabIndex="3"
is next, and so on.tabIndex="0"
(or tabbable by default) has the lowest priority.tabIndex="-1"
(or not tabbable by default) does not act as a tab stop.- For two elements that have the same tabIndex, the one that appears first in the DOM has the higher priority.
tabIndex="1"
具有最高优先级。tabIndex="2"
具有下一个最高优先级。tabIndex="3"
是下一个,依此类推。tabIndex="0"
(或默认情况下可选项卡)具有最低优先级。tabIndex="-1"
(或默认情况下不可制表)不充当制表位。- 对于具有相同 tabIndex 的两个元素,在 DOM 中第一个出现的元素具有更高的优先级。
Here is an example of how to build the list of tab stops, in sequence, using pure Javascript:
以下是如何使用纯 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]);
}
We first walk the DOM, collecting up all tab stops in sequence with their index. We then assemble the final list. Notice that we add the items with tabIndex="0"
at the very end of the list, after the items with a tabIndex
of 1, 2, 3, etc.
我们首先遍历 DOM,按顺序收集所有制表位及其索引。然后我们组装最终的列表。请注意,我们tabIndex="0"
在列表的最后添加了带有 a 的项目,在带有tabIndex
1、2、3 等的项目之后。
For a fully working example, where you can tab around using the "enter" key, check out this fiddle.
回答by Dustin Poissant
function focusNextElement(){
var focusable = [].slice.call(document.querySelectorAll("a, button, input, select, textarea, [tabindex], [contenteditable]")).filter(function($e){
if($e.disabled || ($e.getAttribute("tabindex") && parseInt($e.getAttribute("tabindex"))<0)) return false;
return true;
}).sort(function($a, $b){
return (parseFloat($a.getAttribute("tabindex") || 99999) || 99999) - (parseFloat($b.getAttribute("tabindex") || 99999) || 99999);
});
var focusIndex = focusable.indexOf(document.activeElement);
if(focusable[focusIndex+1]) focusable[focusIndex+1].focus();
};
回答by Wladimir Palant
As mentioned in a comment above, I don't think that any browsers expose tab order information. Here a simplified approximation of what the browser does to get the next element in tab order:
正如上面的评论中提到的,我认为任何浏览器都不会公开 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();
This only considers some tags and ignores tabindex
attribute but might be enough depending on what you are trying to achieve.
这只考虑一些标签并忽略tabindex
属性,但可能就足够了,具体取决于您要实现的目标。
回答by Nate Sullivan
Tabbableis a small JS package that gives you a list of all tabbable elements in tab order. So you could find your element within that list, then focus on the next list entry.
Tabbable是一个小型 JS 包,它为您提供按 Tab 键顺序排列的所有 Tabbable 元素的列表。因此,您可以在该列表中找到您的元素,然后专注于下一个列表条目。
The package correctly handles the complicated edge cases mentioned in other answers (e.g., no ancestor can be display: none
). And it doesn't depend on jQuery!
该包正确处理了其他答案中提到的复杂边缘情况(例如,没有祖先可以是display: none
)。而且它不依赖于 jQuery!
As of this writing (version 1.1.1), it has the caveats that it doesn't support IE8, and that browser bugs prevent it from handling contenteditable
correctly.
在撰写本文时(版本 1.1.1),它有一个警告,即它不支持 IE8,并且浏览器错误会阻止它contenteditable
正确处理。
回答by BrushyAmoeba
This is my first post on SO, so I don't have enough reputation to comment the accepted answer, but I had to modify the code to the following:
这是我在 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()
}
}
}
The changing of var to constant is non-critical. The main change is that we get rid of the selector that checks tabindex != "-1". Then later, if the element has the attribute tabindex AND it is set to "-1", we do NOT consider it focussable.
将 var 更改为常量并不重要。主要的变化是我们去掉了检查 tabindex != "-1" 的选择器。然后,如果元素具有属性 tabindex 并且它被设置为“-1”,我们不认为它是可聚焦的。
The reason I needed to change this was because when adding tabindex="-1" to an <input>
, this element was still considered focussable because it matches the "input[type=text]:not([disabled])" selector. My change is equivalent to "if we are a non-disabled text input, and we have a tabIndex attribute, and the value of that attribute is -1, then we should not be considered focussable.
我需要更改此设置的原因是,将 tabindex="-1" 添加到 an 时<input>
,该元素仍被视为可聚焦,因为它与“input[type=text]:not([disabled])”选择器匹配。我的更改相当于“如果我们是非禁用文本输入,并且我们有一个 tabIndex 属性,并且该属性的值为 -1,那么我们不应该被视为可聚焦。
I believe that when the author of the accepted answer edited their answer to account for the tabIndex attribute, they did not do so correctly. Please let me know if this is not the case
我相信当接受的答案的作者编辑他们的答案以解释 tabIndex 属性时,他们没有正确地这样做。如果不是这种情况,请告诉我