टैब इंडेक्स में अगला तत्व फोकस करें


103

मैं वर्तमान तत्व के आधार पर टैब अनुक्रम में अगले तत्व पर ध्यान केंद्रित करने की कोशिश कर रहा हूं जिसमें फोकस है। इस प्रकार अब तक मैंने अपनी खोजों में कुछ भी नहीं बदला है।

function OnFocusOut()
{
    var currentElement = $get(currentElementId); // ID set by OnFocusIn 

    currentElementId = "";
    currentElement.nextElementByTabIndex.focus();
}

बेशक nextElementByTabIndex इस काम के लिए महत्वपूर्ण हिस्सा है। टैब अनुक्रम में मुझे अगला तत्व कैसे मिलेगा? समाधान JScript का उपयोग करके आधारित होना चाहिए और JQuery की तरह कुछ नहीं।


3
आपके पास यह लाइन क्यों है currentElementId = "";?

1
मुझे नहीं लगता कि कोई भी ब्राउज़र टैब ऑर्डर की जानकारी को उजागर करता है - और ब्राउज़रों द्वारा उपयोग किए गए एल्गोरिथ्म को दोहराने के लिए बहुत जटिल है। शायद आप अपनी आवश्यकताओं को प्रतिबंधित कर सकते हैं, उदाहरण के लिए "केवल विचार करें input, buttonऔर textareaटैग और tabindexविशेषता को अनदेखा करें "।
व्लादिमीर पालंट

हमें आपका .newElementByTabIndexकोड देखने की आवश्यकता है क्योंकि वह काम नहीं कर रहा है।
0x499602D2

2
फिर, शायद विशेष टैग पर प्रतिबंध अनावश्यक है - कोई यह जांच सकता है कि क्या focus()विधि मौजूद है।
व्लादिमीर पालंट

1
@ डेविड वह फ़ंक्शन है जो मौजूद नहीं है, इसलिए मेरा प्रश्न है। : D
JadziaMD

जवाबों:


23

बिना 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;
        }
    }
}

16
हर तत्व में एक नाम जोड़ने के बिना एक समाधान (जैसे कि संभव होने के लिए कई बनाने के तरीके हैं) आदर्श होगा।
जडज़ियाएमडी

3
ठीक है, यह एक फॉर्म के लिए है? इच्छित तत्वों सभी इनपुट तत्व हैं, तो आप लाइन की जगह ले सकता var tabbables = document.getElementsByName("tabable");साथ var tabbables = document.getElementsByTagName("input");बजाय
ब्रायन Glaz

var tabbables = document.querySelectorAll("input, textarea, button")// IE8 +, अपने HTML को संशोधित किए बिना सभी tabbables का एक संदर्भ प्राप्त करें।
ग्रेग

2
class = "tabbable" नाम विशेषता का उपयोग करने के बजाय
क्रिस एफ कैरोल

4
ध्यान दें कि फ्लेक्सबॉक्स का उपयोग करते हुए तत्वों का क्रम ब्राउज़र में नेत्रहीन की तुलना में डोम में भिन्न होता है। जब आप फ्लेक्सबॉक्स का उपयोग करके तत्वों के क्रम को बदलते हैं तो केवल अगले टैब्लेबल तत्व को चुनना काम नहीं करता है।
हनीव

75

मैंने इसे कभी लागू नहीं किया है, लेकिन मैंने एक समान समस्या पर ध्यान दिया है, और यहाँ मैं कोशिश करूँगा।

पहले यह कोशिश करो

सबसे पहले, मैं देखूंगा कि क्या आप उस तत्व पर टैब कुंजी के लिए एक keypressघटना को आग लगा सकते हैं जो वर्तमान में फोकस है। विभिन्न ब्राउज़रों के लिए ऐसा करने का एक अलग तरीका हो सकता है।

अगर वह काम नहीं करता है, तो आपको अधिक मेहनत करनी पड़ेगी ...

JQuery कार्यान्वयन का संदर्भ देते हुए, आपको निम्न करना चाहिए:

  1. टैब और शिफ्ट + टैब के लिए सुनो
  2. जानिए कौन से तत्व हैं टैब-सक्षम
  3. समझें कि टैब ऑर्डर कैसे काम करता है

1. टैब और शिफ्ट + टैब के लिए सुनो

टैब और शिफ्ट + टैब के लिए सुनना शायद वेब पर कहीं और अच्छी तरह से कवर किया गया है, इसलिए मैं उस हिस्से को छोड़ दूंगा।

2. जानें कि कौन से तत्व टैब-सक्षम हैं

यह जानना कि कौन से तत्व टैब-सक्षम हैं, पेचीदा है। मूल रूप से, एक तत्व टैब-सक्षम है यदि यह ध्यान देने योग्य है और इसमें विशेषता tabindex="-1"सेट नहीं है । तो फिर हमें पूछना चाहिए कि कौन से तत्व ध्यान देने योग्य हैं। निम्नलिखित तत्व ध्यान देने योग्य हैं:

  • input, select, textarea, button, और objectतत्वों को अक्षम नहीं कर रहे हैं।
  • aऔर ऐसे areaतत्व जिनके पास सेट के hrefलिए संख्यात्मक मान है या है tabindex
  • किसी भी तत्व को tabindexसेट के लिए एक संख्यात्मक मान है ।

इसके अलावा, एक तत्व केवल तभी ध्यान देने योग्य होता है:

  • इसका कोई भी पूर्वज नहीं है display: none
  • की गणना मूल्य visibilityहै visible। इसका मतलब यह है कि visibilityसेट करने के लिए निकटतम पूर्वज का मान होना चाहिए visible। यदि कोई पूर्वज visibilityनिर्धारित नहीं किया है, तो गणना मूल्य है visible

अधिक जानकारी एक और ढेर अतिप्रवाह उत्तर में हैं

3. समझें कि टैब ऑर्डर कैसे काम करता है

किसी दस्तावेज़ में तत्वों का टैब क्रम tabindexविशेषता द्वारा नियंत्रित किया जाता है। यदि कोई मूल्य निर्धारित नहीं है, तो tabindexप्रभावी रूप से है 0

tabindexदस्तावेज़ के लिए आदेश है: 1, 2, 3, ..., 0।

प्रारंभ में, जब bodyतत्व (या कोई तत्व) पर ध्यान केंद्रित नहीं किया जाता है, तो टैब क्रम में पहला तत्व सबसे कम गैर-शून्य होता है tabindex। यदि कई तत्व समान हैं tabindex, तो आप तब तक दस्तावेज़ क्रम में चले जाते हैं जब तक कि आप अंतिम तत्व उस तक नहीं पहुंच जाते tabindex। फिर आप अगले निम्नतम पर जाते हैं tabindexऔर यह प्रक्रिया जारी रहती है। अंत में, उन तत्वों के साथ एक शून्य (या खाली) के साथ समाप्त करें tabindex


37

इस उद्देश्य के लिए मैं यहां कुछ बना रहा हूं:

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 की जरूरत है
  • सभी आधुनिक ब्राउज़रों में काम करता है
  • तेज और हल्का

2
यह सबसे प्रभावी और संसाधन-अनुकूल समाधान है। धन्यवाद! यहाँ मेरी पूरी स्क्रिप्ट काम कर रही है: stackoverflow.com/a/40686327/1589669
eapo

मैंने स्पष्ट TabIndex focussable.sort (Sort_by_TabIndex) द्वारा छांटने को शामिल करने के लिए नीचे एक स्निपेट जोड़ा
DavB.cs

1
सबसे अच्छा ! यह जटिल होना चाहिए: ध्यान देने nextElementSiblingयोग्य नहीं हो सकता है, अगला ध्यान देने योग्य एक भाई नहीं हो सकता है।
तिनमरीनो

अच्छा दृष्टिकोण, लेकिन यह किसी भी इनपुट के लिए अनुमति देना चाहिए जो प्रकार का नहीं है hiddenऔर कवर भी है textareaऔर select
ल्यूकोरो

23

मैंने एक साधारण jQuery प्लगइन बनाया है जो सिर्फ यही करता है। यह अगले 'tabbable' तत्व को खोजने के लिए jQuery UI का ':' टैबबेबल 'चयनकर्ता का उपयोग करता है और इसका चयन करता है।

उदाहरण का उपयोग:

// Simulate tab key when element is clicked 
$('.myElement').bind('click', function(event){
    $.tabNext();
    return false;
});

8

उत्तर का मूल अगले तत्व को खोजने पर है:

  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


3
यदि दस्तावेज आदेश के खिलाफ टैबइंडेक्स आदेश जाता है तो क्या होगा? मुझे लगता है कि सारणी को टैबइंडेक्स संख्या द्वारा क्रमबद्ध किया जाना चाहिए फिर दस्तावेज़ क्रम से
क्रिस एफ कैरोल

हां, यह अधिक "कल्पना-संगत" होगा। माता-पिता के तत्वों, आदि के बारे में मुझे यकीन नहीं है
एंड्रे वेरलैंग

क्या होगा यदि उन वस्तुओं में से एक जो उन टैगों में से एक नहीं है, एक टैबइंडेक्स विशेषता है?
मैट पेनिंगटन

1
@MattPennington इसे अनदेखा किया जाएगा। फ़िल्टर खोज को गति देने के लिए (एक प्रयास) है, अनुकूलन के लिए स्वतंत्र महसूस करें।
आंद्रे वेरलैंग

3

जैसा कि ऊपर एक टिप्पणी में उल्लेख किया गया है, मुझे नहीं लगता कि कोई भी ब्राउज़र टैब ऑर्डर जानकारी को उजागर करता है। टैब क्रम में अगला तत्व प्राप्त करने के लिए ब्राउज़र क्या करता है, इसका एक सरलीकृत अनुमान है:

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विशेषता को अनदेखा करता है, लेकिन जो आप प्राप्त करने की कोशिश कर रहे हैं, उसके आधार पर पर्याप्त हो सकता है।


3

ऐसा लगता है कि आप tabIndexयह निर्धारित करने के लिए एक तत्व की संपत्ति की जांच कर सकते हैं कि क्या यह ध्यान देने योग्य है। एक तत्व जो ध्यान देने योग्य नहीं है, उसका tabindex"-1" है।

तब आपको केवल टैब स्टॉप के नियमों को जानना होगा:

  • tabIndex="1" सबसे ज्यादा पुजारी है।
  • tabIndex="2" अगली सर्वोच्च प्राथमिकता है।
  • tabIndex="3" अगला है, और इसी तरह।
  • tabIndex="0" (या डिफ़ॉल्ट रूप से सारणीबद्ध) की सबसे कम प्राथमिकता है।
  • 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]);
}

हम सबसे पहले DOM चलते हैं, सभी टैब स्टॉप को उनके सूचकांक के साथ क्रम में एकत्रित करते हैं। हम फिर अंतिम सूची को इकट्ठा करते हैं। ध्यान दें कि हम आइटम tabIndex="0"को सूची के बहुत अंत में जोड़ते हैं, मदों के बाद tabIndex1, 2, 3, आदि के साथ।

पूरी तरह से काम करने वाले उदाहरण के लिए, जहां आप "एंटर" कुंजी का उपयोग करके टैब कर सकते हैं, इस फिडेल को देखें


2

टैब्बल एक छोटा जेएस पैकेज है जो आपको टैब ऑर्डर में सभी टैब्लेबल तत्वों की सूची देता है । तो आप उस सूची में अपना तत्व पा सकते हैं, फिर अगली सूची प्रविष्टि पर ध्यान केंद्रित करें।

पैकेज सही ढंग से अन्य उत्तरों में वर्णित जटिल धार मामलों को संभालता है (जैसे, कोई पूर्वज नहीं हो सकता display: none)। और यह jQuery पर निर्भर नहीं करता है!

इस लेखन के रूप में (संस्करण 1.1.1), इसमें यह चेतावनी दी गई है कि यह IE8 का समर्थन नहीं करता है, और यह कि ब्राउज़र बग इसे contenteditableसही तरीके से संभालने से रोकते हैं ।


2
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();
};

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()
      }                    
  }
}

संस्करण को स्थिरांक में बदलना गैर-महत्वपूर्ण है। मुख्य परिवर्तन यह है कि हम चयनकर्ता से छुटकारा पा लेते हैं जो टैबइंडेक्स की जांच करता है! = "-1"। फिर बाद में, यदि तत्व में विशेषता टैबिन्डेक्स है और यह "-1" पर सेट है, तो हम इसे ध्यान देने योग्य नहीं मानते हैं।

इसे बदलने के लिए मुझे जिस कारण की आवश्यकता थी, वह यह था कि जब tabindex = "- 1" को एक में <input>जोड़ा जाता था, तब भी इस तत्व को फ़ोकस करने योग्य माना जाता था क्योंकि यह "इनपुट [टाइप = टेक्स्ट]: नहीं ([अक्षम])" चयनकर्ता से मेल खाता है। मेरा परिवर्तन इसके बराबर है "यदि हम एक गैर-अक्षम पाठ इनपुट हैं, और हमारे पास एक टैबइंडेक्स विशेषता है, और उस विशेषता का मूल्य -1 है, तो हमें फ़ोकस करने योग्य नहीं माना जाना चाहिए।

मेरा मानना ​​है कि जब स्वीकार किए गए उत्तर के लेखक ने टैबएंडएक्स विशेषता के लिए अपने जवाब को संपादित किया, तो उन्होंने ऐसा सही ढंग से नहीं किया। कृपया मुझे बताएं कि क्या यह मामला नहीं है


1

नहीं है tabindex संपत्ति घटक पर सेट किया जा सकता है। यह निर्दिष्ट करता है कि किस क्रम में इनपुट घटकों को एक का चयन करते समय और टैब दबाने पर पुनरावृत्त होना चाहिए। 0 से ऊपर के मान कस्टम नेविगेशन के लिए आरक्षित हैं, 0 "प्राकृतिक क्रम में" है (इसलिए पहले तत्व के लिए सेट होने पर अलग तरह से व्यवहार करेगा), -1 का मतलब कीबोर्ड फ़ोकस करने योग्य नहीं है:

<!-- navigate with tab key: -->
<input tabindex="1" type="text"/>
<input tabindex="2" type="text"/>

इसे टेक्स्ट इनपुट फ़ील्ड्स की तुलना में कुछ और के लिए भी सेट किया जा सकता है लेकिन यह बहुत स्पष्ट नहीं है कि यह वहाँ क्या करेगा, अगर कुछ भी हो। यहां तक ​​कि अगर नेविगेशन काम करता है, तो बहुत स्पष्ट उपयोगकर्ता इनपुट तत्वों की तुलना में किसी भी चीज़ के लिए "प्राकृतिक ऑर्डर" का उपयोग करना बेहतर होगा।

नहीं, आपको नेविगेशन के इस कस्टम पथ का समर्थन करने के लिए JQuery या किसी भी स्क्रिप्टिंग की आवश्यकता नहीं है। आप इसे बिना किसी जावास्क्रिप्ट समर्थन के सर्वर साइड पर लागू कर सकते हैं। दूसरी तरफ से, संपत्ति रिएक्ट ढांचे में भी ठीक काम करती है, लेकिन इसकी आवश्यकता नहीं होती है।


0

यहां अगले तत्व पर ध्यान केंद्रित करने का एक और अधिक पूर्ण संस्करण है। यह विशिष्ट दिशानिर्देशों का पालन करता है और टैबइंडेक्स का उपयोग करके तत्वों की सूची को सही ढंग से क्रमबद्ध करता है। यदि आप पिछले तत्व प्राप्त करना चाहते हैं, तो भी एक रिवर्स चर परिभाषित किया गया है।

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]);
}

0

यह बढ़िया समाधान है जो @Kano और @Mx ने पेश किया है। यदि आप टैबइंडेक्स ऑर्डर को संरक्षित करना चाहते हैं, तो इस प्रकार को बीच में जोड़ें:

// 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);

0

आप इसे कॉल कर सकते हैं:

टैब:

$.tabNext();

Shift + Tab:

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

मैं jquery.tabbable PlugIn को पूरा करने के लिए संशोधित करता हूं ।


इस उत्तर का डुप्लिकेट , जिसे उस jQuery प्लगइन के निर्माता द्वारा पोस्ट किया गया था।
mbomb007

0

Necromancing।
मेरे पास 0-tabIndexes की एक buch है, जिसे मैं कीबोर्ड से नेविगेट करना चाहता था।
चूंकि उस मामले में, केवल तत्वों के ओआरडीआर ने ही बात की, मैंने इसका उपयोग कियाdocument.createTreeWalker

इसलिए पहले आप फ़िल्टर बनाएं (आप केवल [दृश्यमान] तत्व चाहते हैं, जिसमें NUMERICAL मान के साथ एक विशेषता "tabIndex") है।

फिर आप रूट नोड सेट करते हैं, जिसके आगे आप खोजना नहीं चाहते हैं। मेरे मामले में, this.m_treeएक उल्टा तत्व है जिसमें एक भीगे हुए पेड़ होते हैं। आप पूरे दस्तावेज के बजाय चाहते हैं, बस की जगह this.m_treeके साथ document.documentElement

फिर आप वर्तमान नोड को वर्तमान सक्रिय तत्व पर सेट करते हैं:

ni.currentNode = el; // el = document.activeElement

फिर तुम लौट जाओ ni.nextNode()या ni.previousNode()

नोट:
यदि आपके पास tabIndices! = 0 है तो यह सही क्रम में टैब नहीं लौटाएगा और तत्व क्रम tabIndex क्रम नहीं है। TabIndex = 0 के मामले में, tabOrder हमेशा तत्व क्रम होता है, यही कारण है कि यह काम करता है (उस स्थिति में)।

protected createFilter(fn?: (node: Node) => number): NodeFilter
{
    // Accept all currently filtered elements.
    function acceptNode(node: Node): number 
    {
        return NodeFilter.FILTER_ACCEPT;
    }

    if (fn == null)
        fn = acceptNode;


    // Work around Internet Explorer wanting a function instead of an object.
    // IE also *requires* this argument where other browsers don't.
    const safeFilter: NodeFilter = <NodeFilter><any>fn;
    (<any>safeFilter).acceptNode = fn;

    return safeFilter;
}



protected createTabbingFilter(): NodeFilter
{
    // Accept all currently filtered elements.
    function acceptNode(node: Node): number 
    {
        if (!node)
            return NodeFilter.FILTER_REJECT;

        if (node.nodeType !== Node.ELEMENT_NODE)
            return NodeFilter.FILTER_REJECT;

        if (window.getComputedStyle(<Element>node).display === "none")
            return NodeFilter.FILTER_REJECT;

        // "tabIndex": "0"
        if (!(<Element>node).hasAttribute("tabIndex"))
            return NodeFilter.FILTER_SKIP;

        let tabIndex = parseInt((<Element>node).getAttribute("tabIndex"), 10);
        if (!tabIndex || isNaN(tabIndex) || !isFinite(tabIndex))
            return NodeFilter.FILTER_SKIP;

        // if ((<Element>node).tagName !== "LI") return NodeFilter.FILTER_SKIP;

        return NodeFilter.FILTER_ACCEPT;
    }

    return this.createFilter(acceptNode);
}


protected getNextTab(el: HTMLElement): HTMLElement
{
    let currentNode: Node;
    // https://developer.mozilla.org/en-US/docs/Web/API/Document/createNodeIterator
    // https://developer.mozilla.org/en-US/docs/Web/API/Document/createTreeWalker

    // let ni = document.createNodeIterator(el, NodeFilter.SHOW_ELEMENT);
    // let ni = document.createTreeWalker(this.m_tree, NodeFilter.SHOW_ELEMENT);
    let ni = document.createTreeWalker(this.m_tree, NodeFilter.SHOW_ELEMENT, this.createTabbingFilter(), false);

    ni.currentNode = el;

    while (currentNode = ni.nextNode())
    {
        return <HTMLElement>currentNode;
    }

    return el;
}


protected getPreviousTab(el: HTMLElement): HTMLElement
{
    let currentNode: Node;
    let ni = document.createTreeWalker(this.m_tree, NodeFilter.SHOW_ELEMENT, this.createTabbingFilter(), false);
    ni.currentNode = el;

    while (currentNode = ni.previousNode())
    {
        return <HTMLElement>currentNode;
    }

    return el;
}

ध्यान दें कि जबकि लूप

while (currentNode = ni.nextNode())
{
    // Additional checks here
    // if(condition) return currentNode;
    // else the loop continues;
    return <HTMLElement>currentNode; // everything is already filtered down to what we need here
}

यदि आप चाहते हैं कि आपके पास अतिरिक्त मानदंड हों तो आप केवल उसे बना सकते हैं जिसे आप फ़िल्टर में फ़िल्टर नहीं कर सकते।

ध्यान दें कि यह टाइपस्क्रिप्ट है, आपको कॉलन (:) और कोण-कोष्ठक (<>) के बीच, <Element>या :(node: Node) => numberमान्य जावास्क्रिप्ट प्राप्त करने के लिए सभी टोकन हटाने की आवश्यकता है ।

एक सेवा के रूप में, ट्रांसस्पैन्ड जेएस:

"use strict";
function createFilter(fn) {
    // Accept all currently filtered elements.
    function acceptNode(node) {
        return NodeFilter.FILTER_ACCEPT;
    }
    if (fn == null)
        fn = acceptNode;
    // Work around Internet Explorer wanting a function instead of an object.
    // IE also *requires* this argument where other browsers don't.
    const safeFilter = fn;
    safeFilter.acceptNode = fn;
    return safeFilter;
}
function createTabbingFilter() {
    // Accept all currently filtered elements.
    function acceptNode(node) {
        if (!node)
            return NodeFilter.FILTER_REJECT;
        if (node.nodeType !== Node.ELEMENT_NODE)
            return NodeFilter.FILTER_REJECT;
        if (window.getComputedStyle(node).display === "none")
            return NodeFilter.FILTER_REJECT;
        // "tabIndex": "0"
        if (!node.hasAttribute("tabIndex"))
            return NodeFilter.FILTER_SKIP;
        let tabIndex = parseInt(node.getAttribute("tabIndex"), 10);
        if (!tabIndex || isNaN(tabIndex) || !isFinite(tabIndex))
            return NodeFilter.FILTER_SKIP;
        // if ((<Element>node).tagName !== "LI") return NodeFilter.FILTER_SKIP;
        return NodeFilter.FILTER_ACCEPT;
    }
    return createFilter(acceptNode);
}
function getNextTab(el) {
    let currentNode;
    // https://developer.mozilla.org/en-US/docs/Web/API/Document/createNodeIterator
    // https://developer.mozilla.org/en-US/docs/Web/API/Document/createTreeWalker
    // let ni = document.createNodeIterator(el, NodeFilter.SHOW_ELEMENT);
    // let ni = document.createTreeWalker(this.m_tree, NodeFilter.SHOW_ELEMENT);
    let ni = document.createTreeWalker(document.documentElement, NodeFilter.SHOW_ELEMENT, createTabbingFilter(), false);
    ni.currentNode = el;
    while (currentNode = ni.nextNode()) {
        return currentNode;
    }
    return el;
}
function getPreviousTab(el) {
    let currentNode;
    let ni = document.createTreeWalker(document.documentElement, NodeFilter.SHOW_ELEMENT, createTabbingFilter(), false);
    ni.currentNode = el;
    while (currentNode = ni.previousNode()) {
        return currentNode;
    }
    return el;
}

-1

क्या आपने अपने प्रत्येक टैब के लिए अपने स्वयं के टैब मानों को निर्दिष्ट किया है, जिनके माध्यम से आप साइकिल चलाना चाहते हैं? यदि हां, तो आप यह कोशिश कर सकते हैं:

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 का उपयोग कर रहे हैं, है ना?


हम JQuery का उपयोग नहीं कर रहे हैं क्योंकि यह एप्लिकेशन को तोड़ता है। : /
जडज़ियाएमडी

ठीक है, मुझे लगता है कि मैं फिर से लिख सकता हूं, बिना जेकरी का उपयोग किए, मुझे एक मिनट दे
ब्रायन ग्लेज़

हम जिस भी तत्व में रुचि रखते हैं, उनके टैब इंडेक्स मान सेट होते हैं।
जडज़ियाएमडी

-1

मैंने समाधानों के ऊपर जाँच की और उन्हें काफी लंबा पाया। यह कोड की सिर्फ एक पंक्ति के साथ पूरा किया जा सकता है:

currentElement.nextElementSibling.focus();

या

currentElement.previousElementSibling.focus();

यहाँ currentElement कोई भी अर्थात् document.activeElement हो सकता है या यदि वर्तमान तत्व फ़ंक्शन के संदर्भ में है।

मैंने टैब और शिफ्ट-टैब इवेंट को कीडड इवेंट के साथ ट्रैक किया

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या previousElementSibling.focusविधियों को कर सकते हैं


1
दुर्भाग्य से सिबलिंग ऑर्डर टैब ऑर्डर से संबंधित नहीं है, सिवाय खुश संयोग के, और इसकी कोई गारंटी नहीं है कि प्रचलित / अगला सिबलिंग यहां तक ​​कि ध्यान देने योग्य होगा।
लॉरेंस डॉल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.