按列的垂直顺序设置tabindex

Set tabindex in vertical order of columns

本文关键字:设置 tabindex 顺序 垂直      更新时间:2023-09-26

我正在为我的输入类型文本分配tabindex,这些文本没有被禁用/隐藏。以下是我尝试过的,它很有效。但是,索引的顺序是在表中水平分配的。我需要tabindex的列顺序,而不是水平顺序。有什么建议可以实现吗?我希望订单如下这个Q是这个回车键的后续,以跟随tabindex(在回车键被更改为tab的场景中)。

   col1 col2 col3
    1      3    7
    2      4    8
           5    9 
           6   10  
(":input:not([disabled]):not(:hidden)").not($(":submit")).not($(":reset")).each(function (i) { $(this).attr('tabindex', i + 1); })

此示例将帮助您根据列设置tabindex

function fixVerticalTabindex(selector) {
  if (typeof selector == 'undefined') {
    selector = '.reset-tabindex';
  }
  var tabindex = 1;
  $(selector).each(function(i, tbl) {
    $(tbl).find('tr').first().find('td').each(function(clmn, el) {
      $(tbl).find('tr td:nth-child(' + (clmn + 1) + ') input').each(function(j, input) {
        $(input).attr('placeholder', tabindex);
        $(input).attr('tabindex', tabindex++);
      });
    });
  });
}
$(function() {
  $('#btn-fix').click(function() {
    fixVerticalTabindex('.reset-tabindex');
  });
});
table {
  border: 1px solid red;
}
input {
  border: 1px solid black;
  width: 75px;
  height: 65px;
  font-size: 25px;
  text-align: center;
}
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<table class="reset-tabindex">
  <tr>
    <td><input /></td>
    <td>no input</td>
    <td>no input</td>
  </tr>
  <tr>
    <td>no input</td>
    <td><input /></td>
    <td><input /></td>
  </tr>
  <tr>
    <td><input /></td>
    <td>no input</td>
    <td><input /></td>
  </tr>
</table>
<br /><br />
<table class="reset-tabindex">
  <tr>
    <td><input /></td>
    <td><input /></td>
    <td><input /></td>
    <td><input /></td>
    <td><input /></td>
  </tr>
  <tr>
    <td>no input</td>
    <td>no input</td>
    <td>no input</td>
    <td>no input</td>
    <td><input /></td>
  </tr>
  <tr>
    <td><input /></td>
    <td><input /></td>
    <td><input /></td>
    <td><input /></td>
    <td><input /></td>
  </tr>
  <tr>
    <td>no input</td>
    <td>no input</td>
    <td><input /></td>
    <td><input /></td>
    <td><input /></td>
  </tr>
  <tr>
    <td>no input</td>
    <td>no input</td>
    <td><input /></td>
    <td><input /></td>
    <td><input /></td>
  </tr>
</table>
<br /><br />
<button id="btn-fix">Click to fix vertical tabindex</button>

该函数将自己"修复"每个表(不会在不同表的列之间混合)。

我没有检查colspan/rowspan表的函数,但我猜测它将不能正确工作。

$(input).attr('placeholder', tabindex);行仅用于预览和调试,您可以在生产时删除。

基于这个箭头键的解决方案,我修改了代码,使其也能使用enter键和tab键以及指定的逐列模式。

我不认为为这种情况指定tabindex属性是最好的主意。每次列数或行数发生变化时,都必须重新调用它们。此外,它还将改变页面上可聚焦元素的流(首先是表,然后是其周围的表)。

/*!
* based on formNavigation https://github.com/omichelsen/FormNavigation
*/
(function ($) {
  $.fn.formNavigation = function () {
    $(this).each(function () {
      // Events triggered on keyup
      $(this).find('input').on('keyup', function(e) {
        switch (e.which) {
          // arrow right
          case 39:
            $(this).closest('td').next().find('input').focus();
            break;
          // arrow left
          case 37:
            $(this).closest('td').prev().find('input').focus();
            break;
          // arrow bottom
          case 40:
            $(this).closest('tr').next().children().eq($(this).closest('td').index()).find('input').focus();
            break;
          // arrow top
          case 38:
            $(this).closest('tr').prev().children().eq($(this).closest('td').index()).find('input').focus();
            break;
          // enter
          case 13:
            if ($(this).closest('td').next().find('input').length>0) {
              // when there is another column on right
              $(this).closest('td').next().find('input').focus();
            } else {
              // when last column reached
              $(this).closest('tr').next().children().eq(1).find('input').focus();
            }
            break;
        }
      });
      
      // Events triggered on keydown (repeatable when holding the key)
      $(this).find('input').on('keydown', function(e) {
        // Vertical navigation using tab as OP wanted
        if (e.which === 9 && !e.shiftKey) {
          // navigate forward
          if ($(this).closest('tr').next().find('input').length>0) {
            // when there is another row below
            e.preventDefault();
            $(this).closest('tr').next().children().eq($(this).closest('td').index()).find('input').focus();
          } else if ($(this).closest('tbody').find('tr:first').children().eq($(this).closest('td').index()+1).find('input').length>0) {
            // when last row reached
            e.preventDefault();
            $(this).closest('tbody').find('tr:first').children().eq($(this).closest('td').index()+1).find('input').focus();
          }
        } else if (e.which === 9 && e.shiftKey) {
          // navigate backward
          if ($(this).closest('tr').prev().find('input').length>0) {
            // when there is another row above
            e.preventDefault();
            $(this).closest('tr').prev().children().eq($(this).closest('td').index()).find('input').focus();
          } else if ($(this).closest('tbody').find('tr:last').children().eq($(this).closest('td').index()-1).find('input').length>0) {
            // when first row reached
            e.preventDefault();
            $(this).closest('tbody').find('tr:last').children().eq($(this).closest('td').index()-1).find('input').focus();
          }
        }
      });
    });
  };
})(jQuery);
// usage
$('.gridexample').formNavigation();
/* For demonstration only */
.gridexample {
  font-size: 1.1em;
}
.gridexample th {
  padding: .15em .5em;
}
.gridexample td {
  padding: .1em;
  width: 5em;
}
.gridexample input[type="text"] {
  width: 100%;
  line-height: 2;
  box-sizing: border-box;
}
<p>
  Sample <a href="#">links</a> around the table (to simulate <a href="#">focus</a> outside the table).
</p>
<table class="gridexample">
  <thead>
    <tr>
      <th></th>
      <th>A</th>
      <th>B</th>
      <th>C</th>
      <th>D</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>1</th>
      <td><input type="text"></td>
      <td><input type="text"></td>
      <td><input type="text"></td>
      <td><input type="text"></td>
    </tr>
    <tr>
      <th>2</th>
      <td><input type="text"></td>
      <td><input type="text"></td>
      <td><input type="text"></td>
      <td><input type="text"></td>
    </tr>
    <tr>
      <th>3</th>
      <td><input type="text"></td>
      <td><input type="text"></td>
      <td><input type="text"></td>
      <td><input type="text"></td>
    </tr>
    <tr>
      <th>4</th>
      <td><input type="text"></td>
      <td><input type="text"></td>
      <td><input type="text"></td>
      <td><input type="text"></td>
    </tr>
  </tbody>
</table>
<p>
  Sample <a href="#">links</a> around the table (to simulate <a href="#">focus</a> outside the table).
</p>
<!-- jQuery needed for this solution -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>

从这里的@Merlyn Morgan Graham解决方案我如何使用jQuery在表中从水平到垂直重新分配选项卡顺序?和@dekel的解决方案,我得出了下面的答案。这在大多数情况下都有效。回车键跟随选项卡索引(在回车键被更改为选项卡的情况下)

function assignTabIndex() {
    // Define variables 
    var maxRowCount = 0;        
    // Loop through all rows and find the children (td) length
    // Get the maxRowCount
    $('table tbody tr').each(function() {
        maxRowCount = Math.max(maxRowCount, $(this).children('td').length);        
    });
    // Define and start the cell count at 1
    var cellCounter = 1;
    // Loop through the table, column first instead of row first
    for (var columnIndex = 0; columnIndex < maxRowCount; ++columnIndex) {
        // Loop through all the rows for the current column
        $('form table tr').each(function() {
            // ...but only look at cells matching the current column
            var cellForCurrentColumn = $(this)
                .children('td')
                .eq(columnIndex)
                .find('input[type =text]:not([disabled])');
            // Some rows could be bigger than others,
            // so cellForCurrentColumn might not exist for shorter rows
            if (cellForCurrentColumn != null) {
                // Set the tab index and then increment the counter
                cellForCurrentColumn.attr('tabindex', cellCounter++);
            }
        });
    }
};
// Enter key to follow tab index
   function EnterKeyAsTabKey() {
    $(document).ready(function() {
        assignTabIndex(); //call the assignTabIndex function
        // Will only run once the page Document Object Model (DOM) is ready for JavaScript code 
        // Create a jQuery object containing the html element 'input', and not disabled
        // Create a .not() method to exclude buttons for keypress event
        $(":input:not([disabled])").not($(":button")).keypress(function(evt) {
            // If the keypress event code is 13 (Enter)
            if (event.which === 13 && this.type !== 'submit' || 'reset') {
                evt.preventDefault();
                // Get the attribute type and if the type is not submit
                itype = $(this).prop('type');
                // Get the current Tabindex
                currentTabindex = $(this).attr('tabindex');
                // alert(currentTabindex); // alert to check the value a variable has. Good for trouble shoot
                if (currentTabindex) {
                    nextInput = $('input[tabindex^="' + (parseInt(currentTabindex) + 1) + '"]');
                    // console.log(this, nextInput); // to print next input in console. Good for trouble shoot
                    if (nextInput.length) {
                        nextInput.focus();
                    } else
                        return false;
                }
            }
        });
    })
};

以下是解决方案,如果您的所有输入都在同一级别的div中(假设每个都在Bootstrap col md-*中):

let columns_number=4; // static for me, but you can send/get it via data-columns="4" as form attribute
$('form').find('input, select, textarea').each(function(){
    $(this).attr('tabindex', $(this).attr('type')==='submit' ? 999 : $(this).closest('div').index()%columns_number+1);
});

JSFiddle:https://jsfiddle.net/x5oh7edf/