Sekme Dizinindeki Sonraki Öğeye Odaklan


103

Odağı mevcut öğeye bağlı olarak sekme dizisindeki sonraki öğeye taşımaya çalışıyorum. Şimdiye kadar aramalarımda hiçbir şey ortaya koymadım.

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

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

Tabii ki nextElementByTabIndex bunun çalışması için anahtar kısımdır. Sekme dizisindeki sonraki öğeyi nasıl bulabilirim? Çözümün JQuery gibi bir şey değil, JScript kullanılarak temel alınması gerekir.


3
Neden bu satırı var mı currentElementId = "";?

1
Hiçbir tarayıcının sekme sırası bilgilerini açığa çıkardığını sanmıyorum - ve tarayıcılar tarafından kullanılan algoritma çoğaltılamayacak kadar karmaşık. Belki örn ihtiyaçlarınızı kısıtlayabilir "sadece düşünün input, buttonve textareaetiketleri ve görmezden tabindexniteliği".
Wladimir Palant

.newElementByTabIndexKodunuzu görmemiz gerekiyor çünkü bu işe yaramıyor.
0x499602D2

2
Sonra tekrar, belki belirli etiketlere kısıtlama gereksiz olabilir - focus()yöntemin var olup olmadığı kontrol edilebilir .
Wladimir Palant

1
@David Bu var olmayan işlev, bu yüzden benim sorum. : D
JadziaMD

Yanıtlar:


24

Jquery olmadan: Öncelikle, sekmeli öğelerinize eklemek, class="tabable"onları daha sonra seçmemize izin verecektir. (Aşağıdaki kodda bulunan "." Sınıf seçici önekini unutmayın)

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
Her unsura bir isim eklemek zorunda kalmadan bir çözüm (mümkünse yapmanın birçok yolu olduğu için) ideal olacaktır.
JadziaMD

3
tamam, bu bir form için mi? İstediğiniz unsurların tüm giriş elemanları iseniz, hattı yerini var tabbables = document.getElementsByName("tabable");ile var tabbables = document.getElementsByTagName("input");yerine
Brian Glaz

var tabbables = document.querySelectorAll("input, textarea, button")// IE8 +, HTML'nizi değiştirmeden tüm sekme tablolarına bir referans alın.
Greg

2
name özelliğini kullanmak yerine class = "tabbable"
Chris F Carroll

4
Flexbox kullanıldığında, DOM'daki öğelerin sırasının tarayıcıdakinden farklı olduğunu unutmayın. Flexbox kullanarak öğelerin sırasını değiştirdiğinizde sadece bir sonraki sekmeli öğeyi seçmek işe yaramaz.
Haneev

75

Bunu hiç uygulamadım, ancak benzer bir soruna baktım ve işte deneyeceğim şey.

Önce bunu dene

İlk önce, bir olayı basitçe tetikleyebilir misin diye bakardımkeypress şu anda odağı olan öğede Sekme tuşu için . Farklı tarayıcılar için bunu yapmanın farklı bir yolu olabilir.

Bu işe yaramazsa, daha çok çalışmanız gerekecek ...

JQuery uygulamasına başvurarak şunları yapmanız gerekir:

  1. Sekme ve Shift + Sekmeyi Dinle
  2. Hangi öğelerin sekmeli olduğunu öğrenin
  3. Sekme sırasının nasıl çalıştığını anlayın

1. Sekme ve Shift + Sekme'yi dinleyin

Tab ve Shift + Tab için dinleme muhtemelen web'de başka bir yerde iyi bir şekilde ele alınmıştır, bu yüzden o bölümü atlayacağım.

2. Hangi öğelerin sekmeli olduğunu öğrenin

Hangi öğelerin sekmeli olduğunu bilmek daha zordur. Temel olarak, bir öğe odaklanabilirse ve öznitelik tabindex="-1"kümesine sahip değilse sekme ile kullanılabilir . Öyleyse hangi öğelerin odaklanılabilir olduğunu sormalıyız. Aşağıdaki unsurlar odaklanabilir:

  • input, select, textarea, button, Ve objectelemanları devre dışı olmadığını.
  • ave set için areabir hrefveya sayısal bir değeri olan öğeler tabindex.
  • tabindexküme için sayısal bir değeri olan herhangi bir öğe .

Ayrıca, bir öğeye yalnızca şu durumlarda odaklanabilir:

  • Atalarından hiçbiri değil display: none.
  • Hesaplanmış değeri visibilityolan visible. Bu, kümelenecek en yakın atanın visibilitydeğerine sahip olması gerektiği anlamına gelir visible. Hiçbir ata visibilityayarlanmadıysa, hesaplanan değer olur visible.

Daha fazla ayrıntı başka bir Stack Overflow yanıtında .

3. Sekme sırasının nasıl çalıştığını anlayın

Bir belgedeki öğelerin sekme sırası tabindexöznitelik tarafından kontrol edilir . Hiçbir değer ayarlanmadıysa, tabindexetkin0 .

tabindexBelge için sıradır: 1, 2, 3, ..., 0.

Başlangıçta, bodyöğenin (veya hiçbir öğenin) odağı olduğunda, sekme sırasındaki ilk öğe sıfır olmayan en düşük öğedir tabindex. Birden fazla öğenin aynısı varsa tabindex, onunla son öğeye ulaşana kadar belge sırasına girersiniz tabindex. Sonra bir sonraki en alçak seviyeye geçersiniz tabindexve süreç devam eder. Son olarak, bu öğeleri sıfır (veya boş) ile bitirin tabindex.


37

İşte bu amaç için oluşturduğum bir şey:

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

Özellikleri:

  • yapılandırılabilir odaklanabilir öğeler kümesi
  • jQuery gerekmez
  • tüm modern tarayıcılarda çalışır
  • hızlı ve hafif

2
Bu, en etkili ve kaynak dostu çözümdür. Teşekkür ederim! İşte tam çalışma komut
dosyam

TabIndex focussable.sort (sort_by_TabIndex)
DavB.cs

1
En iyisi ! O kadar karmaşık olmalı : nextElementSiblingodaklanılamayabilir, bir sonraki odaklanılabilir olan bir kardeş olmayabilir.
Tinmarino

İyi bir yaklaşım, ancak türde olmayan herhangi bir girdiye izin vermelidir hidden ve ayrıca textareave select.
Lucero

23

Sadece bunu yapan basit bir jQuery eklentisi oluşturdum. Bir sonraki 'sekmeli' öğeyi bulmak için jQuery kullanıcı arayüzünün ': tabbable' seçicisini kullanır ve onu seçer.

Örnek kullanım:

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

8

Cevabın özü, bir sonraki unsuru bulmakta yatıyor:

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

Kullanım:

var nextEl = findNextTabStop(element);
nextEl.focus();

Önceliklendirme umurumda değil tabIndex.


3
Ya tabindex sırası belge sırasına aykırı olursa? Dizinin tabindex numarasına ve ardından belge sırasına göre sıralanması gerektiğini düşünüyorum
Chris F Carroll

Evet, bu daha "spesifikasyon uyumlu" olurdu. Ebeveyn unsurları vb.
İle

Ya bu etiketlerden biri olmayan bir öğenin bir tabindex özelliği varsa?
Matt Pennington

1
@MattPennington Görmezden gelinir. Filtre, aramayı hızlandırmak için (bir girişimdir), uyum sağlamaktan çekinmeyin.
André Werlang

3

Yukarıdaki bir yorumda belirtildiği gibi, hiçbir tarayıcının sekme sırası bilgilerini açığa çıkardığını sanmıyorum. Burada, tarayıcının bir sonraki öğeyi sekme sırasına göre elde etmek için ne yaptığının basitleştirilmiş bir tahmini:

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

Bu yalnızca bazı etiketleri dikkate alır ve tabindexözniteliği yok sayar , ancak elde etmeye çalıştığınız şeye bağlı olarak yeterli olabilir.


3

tabIndexOdaklanabilir olup olmadığını belirlemek için bir öğenin özelliğini kontrol edebilirsiniz gibi görünüyor . Odaklanamayan bir öğenin birtabindex "-1" değeri vardır.

O zaman sekme duraklarının kurallarını bilmeniz yeterlidir:

  • tabIndex="1" en yüksek önceliğe sahiptir.
  • tabIndex="2" bir sonraki en yüksek önceliğe sahiptir.
  • tabIndex="3" sonraki, vb.
  • tabIndex="0" (veya varsayılan olarak sekmeli) en düşük önceliğe sahiptir.
  • tabIndex="-1" (veya varsayılan olarak sekmeli değildir) sekme durağı olarak işlev görmez.
  • Aynı tabIndex'e sahip iki öğe için, DOM'da ilk görünen öğe daha yüksek önceliğe sahiptir.

Aşağıda, saf Javascript kullanarak sekme durakları listesinin nasıl sırayla oluşturulacağına dair bir örnek verilmiştir:

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

Önce DOM'u gezerek tüm sekme duraklarını dizinlerine göre sıralıyoruz. Daha sonra son listeyi bir araya getiriyoruz. İle öğeleri tabIndex="0"listenin en sonuna, işaretli öğelerden sonra eklediğimize dikkat edin.tabIndex 1, 2, 3, vb. .

"Enter" tuşunu kullanarak etrafta dolaşabileceğiniz tam anlamıyla çalışan bir örnek için, bu kemana bir bakın .


2

Tabbable , size sekme sırasına göre tüm sekmeli öğelerin bir listesini veren küçük bir JS paketidir . Böylece, öğenizi bu listede bulabilir ve ardından bir sonraki liste girişine odaklanabilirsiniz.

Paket, diğer yanıtlarda belirtilen karmaşık uç durumları doğru bir şekilde ele alır (örneğin, hiçbir ata olamaz display: none ). Ve jQuery'ye bağlı değildir!

Bu yazı itibariyle (sürüm 1.1.1), IE8'i desteklemediğine ve tarayıcı hatalarının contenteditabledoğru şekilde işlemesini engellediğine dair uyarılara sahiptir .


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

Bu, SO'daki ilk gönderim, bu yüzden kabul edilen yanıtı yorumlamak için yeterli itibarım yok, ancak kodu aşağıdaki şekilde değiştirmem gerekiyordu:

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

Var'ın sabite değiştirilmesi kritik değildir. Ana değişiklik, tabindex! = "-1" i kontrol eden seçiciden kurtulmamızdır. Daha sonra, öğe tabindex niteliğine sahipse VE "-1" olarak ayarlanmışsa, odaklanabilir olduğunu DEĞİLDİR.

Bunu değiştirmem gerekmesinin nedeni, tabindex = "- 1" <input>öğesini bir öğesine eklerken, bu öğenin "input [type = text]: not ([disabled])" seçiciyle eşleştiği için hala odaklanabilir olarak kabul edilmesiydi. Benim değişikliğim "devre dışı bırakılmamış bir metin girdiysek ve bir tabIndex özelliğimiz varsa ve bu özelliğin değeri -1 ise, odaklanabilir olarak değerlendirilmemeliyiz.

Kabul edilen cevabın yazarı, tabIndex özniteliğini hesaba katmak için yanıtını düzenlediğinde, bunu doğru yapmadıklarına inanıyorum. Lütfen durum böyle değilse bana bildirin


1

Orada tabindex bileşeni üzerinde ayarlanabilir özelliği. Birini seçip sekmeye basarken giriş bileşenlerinin hangi sırayla yinelenmesi gerektiğini belirtir. 0'ın üzerindeki değerler özel gezinme için ayrılmıştır, 0 "doğal sıradadır" (bu nedenle ilk öğe için ayarlandıysa farklı davranır), -1 klavyeye odaklanılamaz anlamına gelir:

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

Metin giriş alanlarından başka bir şeye de ayarlanabilir, ancak orada ne yapacağı çok açık değildir. Gezinme çalışsa bile, çok bariz kullanıcı girdi öğelerinden başka herhangi bir şey için "doğal düzen" kullanmak daha iyi olabilir.

Hayır, bu özel gezinme yolunu desteklemek için JQuery'ye veya herhangi bir komut dosyasına ihtiyacınız yoktur. Herhangi bir JavaScript desteği olmadan sunucu tarafında uygulayabilirsiniz. Diğer taraftan, özellik de React çerçevesinde iyi çalışıyor ancak bunu gerektirmiyor.


0

İşte bir sonraki öğeye odaklanmanın daha eksiksiz bir versiyonu. Spesifikasyon yönergelerine uyar ve tabindex'i kullanarak elemanların listesini doğru bir şekilde sıralar. Ayrıca önceki elemanı almak istiyorsanız bir ters değişken tanımlanır.

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

Bu, @Kano ve @Mx'in sunduğu harika çözüme yönelik potansiyel bir iyileştirmedir . TabIndex sıralamasını korumak istiyorsanız ortada bu sıralamayı ekleyin:

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

Bunu arayabilirsin:

Sekme:

$.tabNext();

Üst Karakter + Sekme:

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

Tamamlamak için jquery.tabbable PlugIn'i değiştiriyorum .


Kopyası Bu cevap o jQuery eklentisi yaratıcısı tarafından yayınlanmıştır.
mbomb007

0

Büyüleyici.
Klavye ile gezinmek istediğim bir grup 0-tabIndexes var.
Bu durumda, yalnızca öğelerin SİPARİŞİ önemli olduğundan, bunu kullanarak yaptımdocument.createTreeWalker

Bu nedenle, önce filtreyi oluşturursunuz (yalnızca SAYISAL değeri olan bir "tabIndex" özniteliğine sahip [görünür] öğeleri istersiniz.

Ardından, ötesinde arama yapmak istemediğiniz kök düğümü ayarlarsınız. Benim durumumda, değiştirilebilir this.m_treebir ağaç içeren bir ul öğesidir. Bunun yerine belgenin tamamını istiyorsanız, this.m_treeşununla değiştirin:document.documentElement .

Ardından, geçerli düğümü geçerli etkin öğeye ayarlarsınız:

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

Sonra dönersiniz ni.nextNode()veya ni.previousNode().

Not:
eğer tabIndices! = 0'a sahipseniz ve eleman sırası tabIndex sırası DEĞİLSE, sekmeleri doğru sırayla döndürmez. TabIndex = 0 olması durumunda, tabOrder her zaman eleman sırasıdır, bu yüzden bu çalışır (bu durumda).

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 döngüsünün

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
}

Yalnızca, createTreeWalker'a geçirilen filtrede filtreleyemeyeceğiniz ek kriterleriniz varsa, oradadır.

Bunun TypeScript olduğunu unutmayın, iki nokta üst üste işaretlerinin (:) arkasındaki ve açılı ayraçlar (<>) arasındaki tüm simgeleri kaldırmanız gerekir, örneğin <Element>veya:(node: Node) => number geçerli bir JavaScript olsun.

Burada bir hizmet olarak, aktarılan JS:

"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

Dönmek istediğiniz her öğe için kendi tabIndex değerlerinizi belirlediniz mi? eğer öyleyse, şunu deneyebilirsiniz:

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 kullanıyorsun, değil mi?


Uygulamayı bozduğu için JQuery kullanmıyoruz. : /
JadziaMD

Tamam, sanırım jquery kullanmadan yeniden yazabilirim, bana bir dakika ver
Brian Glaz

İlgilendiğimiz her öğenin kendi sekme indeksi değerleri vardır.
JadziaMD

-1

Yukarıdaki çözümleri kontrol ettim ve oldukça uzun buldum. Yalnızca bir satır kodla gerçekleştirilebilir:

currentElement.nextElementSibling.focus();

veya

currentElement.previousElementSibling.focus();

burada currentElement herhangi bir ie document.activeElement olabilir veya geçerli öğe işlev bağlamında ise bu olabilir.

Keydown olayı ile sekme ve shift-tab olaylarını izledim

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 == '';
    }
});

imleç yönüne sahip olduğunuzda, nextElementSibling.focusveya previousElementSibling.focusyöntemlerini kullanabilirsiniz


1
Ne yazık ki kardeş sıralaması, mutlu tesadüfler dışında sekme sırasına bağlı değildir ve önceki / sonraki kardeşin odaklanabilir olacağının garantisi bile yoktur.
Lawrence Dol
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.