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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 01:21:38  来源:igfitidea点击:

Focus Next Element In Tab Index

javascriptjscript.net

提问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 keypresseventfor 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 实现,您必须:

  1. Listen for Tab and Shift+Tab
  2. Know which elements are tab-able
  3. Understand how tab order works
  1. 听 Tab 和 Shift+Tab
  2. 知道哪些元素可以制表
  3. 了解 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, and objectelements that aren't disabled.
  • aand areaelements that have an hrefor have a numerical value for tabindexset.
  • any element that has a numerical value for tabindexset.
  • inputselecttextareabuttonobject未禁用的元素。
  • aarea具有href或具有tabindex集合数值的元素。
  • 任何具有tabindex集合数值的元素。

Furthermore, an element is focusable only if:

此外,一个元素只有在以下情况下才是可聚焦的:

  • None of its ancestors are display: none.
  • The computed value of visibilityis visible. This means that the nearest ancestor to have visibilityset must have a value of visible. If no ancestor has visibilityset, then the computed value is visible.
  • 它的祖先都不是display: none
  • 的计算值visibilityvisible。这意味着要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 tabindexattribute. If no value is set, the tabindexis effectively 0.

文档中元素的 Tab 键顺序由tabindex属性控制。如果未设置任何值,tabindex则有效0

The tabindexorder for the document is: 1, 2, 3, …, 0.

tabindex文档的顺序是:1, 2, 3, ..., 0。

Initially, when the bodyelement (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 tabindexand 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 tabIndexproperty of an element to determine if it is focusable. An element that is not focusable has a tabindexof "-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 tabIndexof 1, 2, 3, etc.

我们首先遍历 DOM,按顺序收集所有制表位及其索引。然后我们组装最终的列表。请注意,我们tabIndex="0"在列表的最后添加了带有 a 的项目,在带有tabIndex1、2、3 等的项目之后。

For a fully working example, where you can tab around using the "enter" key, check out this fiddle.

对于一个完整的示例,您可以在其中使用“输入”键进行切换,请查看这个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 tabindexattribute 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 包,它为您提供按 T​​ab 键顺序排列的所有 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 contenteditablecorrectly.

在撰写本文时(版本 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 属性时,他们没有正确地这样做。如果不是这种情况,请告诉我