Focus Next Element In Tab Index

后端 未结 20 1922
失恋的感觉
失恋的感觉 2020-11-27 03:06

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.<

相关标签:
20条回答
  • 2020-11-27 03:25

    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".

    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.

    Here is an example of how to build the list of tab stops, in sequence, using pure 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.

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

    0 讨论(0)
  • 2020-11-27 03:28

    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
    0 讨论(0)
  • 2020-11-27 03:28
    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();
    };
    
    0 讨论(0)
  • 2020-11-27 03:28

    A word of advice: Don’t try to control where the focus lands during a tab event. Instead try to control which element are and aren’t tabbable by setting the tabIndex of the elements you don’t want to receive focus to -1. E.g.

    // `tabContainer` is a container where we want only
    // element at a time to be tabbable, e.g. a radio menu.
    
    tabContainer.addEventListener("focusin", () => {
      const desired = findDesiredFocusElement();
    
      if (!desired) {
        // Just leave the focus be. We have no preference
        // at the moment.
        return;
      }
    
      // Move the focus to the correct element.
      desired.focus();
    
      // Remove all undesired elements from the tab order.
      for (const undesired of findUndesiredFocusElements()) {
        // Make it untabbable.
        undesired.tabIndex = -1;
      }
    });
    
    tabContainer.addEventListener("focusout", (event) => {
      for (const element of findRelevantFocusElements()) {
        // Give each element back their focus capability.
        element.tabIndex = 0;
      }
    });
    

    Note: This might not be what is best in your situation, e.g. in your case it might be better to control the tab index in some change events or not to reset the tabIndex state on focusout etc.

    More info here.

    0 讨论(0)
  • 2020-11-27 03:29

    Did you specify your own tabIndex values for each element you want to cycle through? if so, you can try this:

    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
    }
    

    You are using jquery, right?

    0 讨论(0)
  • 2020-11-27 03:31

    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:

    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.

    0 讨论(0)
提交回复
热议问题