タブインデックスの次の要素にフォーカス


103

フォーカスがある現在の要素に基づいて、タブシーケンスの次の要素にフォーカスを移動しようとしています。これまでのところ、検索で何も調べていません。

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

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

もちろん、nextElementByTabIndexは、これが機能するための重要な部分です。タブシーケンスで次の要素を見つけるにはどうすればよいですか?ソリューションは、JQueryのようなものではなく、JScriptを使用してベースにする必要があります。


3
なぜあなたはこのラインを持っているのcurrentElementId = "";ですか?

1
どのブラウザーもタブオーダー情報を公開しているとは思いません。ブラウザー自体が使用するアルゴリズムは複雑すぎて複製できません。たぶん、あなたは例えば「のみを検討し、要件を制限することができinputbuttonかつtextareaタグと無視tabindex属性を」。
ウラジミールパラント

.newElementByTabIndexコードが機能していないため、コードを確認する必要があります。
0x499602D2

2
繰り返しになりますが、おそらく特定のタグへの制限は不要focus()です。メソッドが存在するかどうかを確認できます。
ウラジミールパラント

1
@Davidそれは存在しない関数なので、私の質問です。:D
JadziaMD '26 / 08/26

回答:


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
すべての要素に名前を追加する必要がないソリューション(可能な場合は多くの人が作成できる方法があるため)が理想的です。
JadziaMD、2011

3
わかりました、これはフォーム用ですか?必要なすべての要素が入力要素である場合var tabbables = document.getElementsByName("tabable");var tabbables = document.getElementsByTagName("input");代わりに行を置き換えることができます
Brian Glaz '26

var tabbables = document.querySelectorAll("input, textarea, button")// IE8 +、HTMLを変更せずにすべてのタブ可能オブジェクトへの参照を取得します。
グレッグ

2
name属性を使用するのではなく、class = "tabbable"
Chris F Carroll

4
フレックスボックスを使用すると、要素の順序がブラウザでの視覚的なものとはDOMで異なることに注意してください。フレックスボックスを使用して要素の順序を変更すると、次のタブ可能な要素を選択するだけでは機能しません。
ハネエフ

75

私はこれを実装したことがありませんが、同様の問題を調査しました。ここで私が試してみます。

まずこれを試してください

あなたは、単にできれば最初に、私は見ることが火災keypressのイベントを、現在フォーカスを持っている要素上のTabキーのために。ブラウザーごとにこれを行う別の方法があるかもしれません。

それでもうまくいかない場合は、もっと頑張らなければなりません…

jQuery実装を参照するには、次のことを行う必要があります。

  1. TabとShift + Tabを聞く
  2. タブ可能な要素を知る
  3. タブオーダーの仕組みを理解する

1. TabとShift + Tabを聞く

TabとShift + Tabのリッスンは、おそらくWeb上の他の場所で十分にカバーされているので、その部分はスキップします。

2.タブ可能な要素を知る

タブ可能な要素を知るのは難しいです。基本的に、要素がフォーカス可能で属性がtabindex="-1"設定されていない場合、要素はタブ可能です。したがって、どの要素がフォーカス可能であるかを尋ねる必要があります。次の要素にフォーカスできます。

  • inputselecttextareabutton、および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フォーカスできないかもしれません、次のフォーカス可能なものは兄弟ではないかもしれません。
Tinmarino

良いアプローチですが、タイプではなく、hiddenおよびをカバーする入力を許可する必要がtextareaありselectます。
Lucero

23

これを行う単純なjQueryプラグインを作成しました。jQuery UIの「:tabbable」セレクターを使用して、次の「tabbable」要素を見つけて選択します。

使用例:

// 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
tabindexの順序がドキュメントの順序に反する場合はどうなりますか?配列はtabindex番号で、次にドキュメントの順序でソートする必要があると思います
Chris F Carroll

うん、それはより「仕様に準拠」するでしょう。私は親要素などについては、エッジ例についてはよく分からない
アンドレ・Werlang

これらのタグではないアイテムにtabindex属性がある場合はどうなりますか?
マットペニントン

1
@MattPennington無視されます。フィルタは(試み)検索を高速化するためのものです。自由に変更してください。
アンドレ・Werlang

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" (またはデフォルトではタブ移動不可)はタブストップとして機能しません。
  • 同じtabIndexを持つ2つの要素の場合、DOMで最初に表示される要素が優先されます。

以下は、純粋な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]);
}

最初にDOMをウォークし、すべてのタブストップをインデックスで順に収集します。次に、最終的なリストを作成します。tabIndex="0"リストの一番最後にあるアイテムを追加したことに注意してください。tabIndexが1、2、3などの。

「Enter」キーを使用してタブで移動できる完全に機能する例については、このフィドルをチェックしてください。


2

Tabbableは、すべてのタブ可能な要素のリストをタブ順に並べた小さなJSパッケージです。そのため、そのリスト内で要素を見つけ、次のリストエントリに焦点を当てることができます。

パッケージは、他の回答で言及されている複雑なエッジケースを正しく処理します(たとえば、祖先は 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

これは私の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()
      }                    
  }
}

varからconstantへの変更は重要ではありません。主な変更は、tabindex!= "-1"をチェックするセレクターを取り除くことです。その後、要素に属性tabindexがあり、かつ「-1」に設定されている場合、フォーカス可能とは見なされません。

これを変更する必要があった理由は、tabindex = "-1"をに追加したときに<input>、 "input [type = text]:not([disabled])"セレクターと一致するため、この要素は依然としてフォーカス可能と見なされていたためです。私の変更は、「無効になっていないテキスト入力で、tabIndex属性があり、その属性の値が-1の場合、フォーカス可能とは見なされません。

受け入れられた回答の作成者がtabIndex属性を考慮して回答を編集したときに、正しく編集されなかったと思います。そうでない場合はお知らせください


1

コンポーネントに設定できるtabindexプロパティがあります。これは、1つを選択してタブを押すときに、入力コンポーネントを反復する順序を指定します。0より大きい値はカスタムナビゲーション用に予約されており、0は「自然順」です(したがって、最初の要素に設定すると動作が異なります)。-1はキーボードフォーカス不可を意味します。

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

テキスト入力フィールド以外に設定することもできますが、それが何であるかは明らかではありません。ナビゲーションが機能しても、非常に明白なユーザー入力要素以外には「自然な順序」を使用する方がよいでしょう。

いいえ、このナビゲーションのカスタムパスをサポートするために、JQueryやスクリプトはまったく必要ありません。JavaScriptのサポートがなくても、サーバー側で実装できます。反対側から見ると、このプロパティはReactフレームワークでも問題なく機能しますが、必須ではありません。


0

これは、次の要素に焦点を当てたより完全なバージョンです。仕様ガイドラインに従い、tabindexを使用して要素のリストを正しく並べ替えます。また、前の要素を取得したい場合は、reverse変数が定義されます。

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が提供した優れたソリューションの潜在的な機能強化 です。TabIndexの順序を維持したい場合は、このソートを中央に追加します。

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

ネクロマンシング。
私はキーボードでナビゲートしたかった0-tabIndexesをたくさん持っています。
その場合、要素の順序のみが重要であるため、私はそれを使用してそれを行いましたdocument.createTreeWalker

したがって、最初にフィルターを作成します(数値の値を持つ「tabIndex」属性を持つ[visible]要素のみが必要です)。

次に、ルートノードを設定します。これを超えると検索しないようにします。私の場合、this.m_treeトグル可能なツリーを含むul要素です。代わりにドキュメント全体が必要な場合は、に置き換え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ループが

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
}

createTreeWalkerに渡されるフィルターでフィルター処理できない追加の基準がある場合にのみ必要です。

これはTypeScriptであることに注意してください。たとえば、コロン(:)の後ろ、および山かっこ(<>)の間のすべてのトークンを削除する必要があります。<Element>または:(node: Node) => number、有効なJavaScriptを取得します。

ここではサービスとして、積み重ねられた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

循環させたい要素ごとに独自のtabIndex値を指定しましたか?もしそうなら、あなたはこれを試すことができます:

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は使用していません。:/
JadziaMD

わかりました、jqueryを使用せずに書き換えることができると思います。少し待ってください
ブライアングラーツ

対象となるすべての要素には、タブインデックス値が設定されています。
JadziaMD、2011

-1

上記の解決策を確認したところ、かなり長いことがわかりました。これは、たった1行のコードで実現できます。

currentElement.nextElementSibling.focus();

または

currentElement.previousElementSibling.focus();

ここでcurrentElementは任意のもの、つまりdocument.activeElement、または現在の要素が関数のコンテキストにある場合はthisです。

keydownイベントでタブとシフトタブのイベントを追跡しました

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
残念ながら、兄弟の順序はタブ順とは関係ありませんが、偶然の一致を除いて、前/次の兄弟がフォーカス可能である保証さえありません。
ローレンスドル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.