模拟按下TAB键:根据`tabIndex`确定下一个元素的聚焦。

24

我有两个输入元素,第一个元素已经聚焦,我想通过模拟 TAB 键的按下/松开事件来聚焦到第二个元素。(注意:我不想使用 .next() 或其他方法。)

这是我的代码,灵感来自于这个问题

$('input').first().focus();

var e = $.Event('keydown');

e.which = 9; // TAB
$(':focus').trigger(e);
请参考http://jsfiddle.net/3PcPH/。这段代码不起作用,出了什么问题?

@mu太短了:是的,没错!我已经寻找这个东西很久了。请帮忙。 - Randomblue
你的表单元素上实际上都有 tabindex 属性吗? - mu is too short
不。这对我来说似乎是一件非常琐碎的事情。然而... - Randomblue
5个回答

35

使用Javascript没有简单的编程方法来实现这个...所以这里有一种蛮力方式。

根据W3:

可以接收焦点的元素应该按照以下规则由用户代理进行导航:

  1. 支持tabindex属性并为其分配正值的那些元素首先被导航。导航从具有最低tabindex值的元素开始,到具有最高值的元素结束。值不需要连续,也不必以任何特定值开头。具有相同tabindex值的元素应按它们在字符流中出现的顺序进行导航。
  2. 不支持tabindex属性或支持它并将其分配为“0”的那些元素紧随其后。这些元素按它们在文档中出现的顺序进行导航。
  3. 禁用的元素不参与制表顺序。

我通过存储表单中具有tabIndex> 0的元素的tabIndex顺序来实现此目的,然后按照它们在文档中出现的顺序连接其余元素。以下代码模拟了在聚焦于表单输入时按下tab键,然后按下字母'z'(但您可以将其更改为您需要的任何条件):

$(':input').keypress(function(e){ 

    // if 'z' pressed
    if (e.which == 122) {

        // if we haven't stored the tabbing order
        if (!this.form.tabOrder) {

            var els = this.form.elements,
                ti = [],
                rest = [];

            // store all focusable form elements with tabIndex > 0
            for (var i = 0, il = els.length; i < il; i++) {
                if (els[i].tabIndex > 0 &&
                    !els[i].disabled && 
                    !els[i].hidden && 
                    !els[i].readOnly &&
                    els[i].type !== 'hidden') {
                    ti.push(els[i]);
                }
            }

            // sort them by tabIndex order
            ti.sort(function(a,b){ return a.tabIndex - b.tabIndex; });

            // store the rest of the elements in order
            for (i = 0, il = els.length; i < il; i++) {
                if (els[i].tabIndex == 0 &&
                    !els[i].disabled && 
                    !els[i].hidden && 
                    !els[i].readOnly &&
                    els[i].type !== 'hidden') {
                    rest.push(els[i]);
                }
            }

            // store the full tabbing order
            this.form.tabOrder = ti.concat(rest);
        }

        // find the next element in the tabbing order and focus it
        // if the last element of the form then blur
        // (this can be changed to focus the next <form> if any)
        for (var j = 0, jl = this.form.tabOrder.length; j < jl; j++) {
            if (this === this.form.tabOrder[j]) {
                if (j+1 < jl) {
                    $(this.form.tabOrder[j+1]).focus();
                } else {
                    $(this).blur();
                }
            }
        }

    }

});

查看演示


谢谢!我在 Chrome 中注意到两个不一致之处。1)使用 z 将更改第三个可聚焦元素的内容为 z。2)当没有元素聚焦时,TAB 将聚焦 FIRSTz 则无动作。 - Randomblue
@Randomblue 1) 按下“z”只是一个示例触发器,我假设这将以某种方式通过编程处理。如果需要,您可以添加e.preventDefault()。2) 您也可以通过将触发器添加到$('document')来更改此设置,但从您的要求中听起来,您只想在表单输入上使用此功能。 - mVChr
如果在keypress函数的最后一部分添加'return false;',它将不会将'z'输入到下一个文本框中,因为返回false会阻止浏览器对你最初执行的keypress事件进行任何操作(但只在捕获事件上返回false,否则所有输入都将被捕获)。 - JakeJ
1
jQuery UI有:tabbable:focusable伪选择器。如果您想将此类内容作为库引入,只需要jquery-ui.core.js即可。 - willscripted
注意了... event.which 已经被弃用,应该使用 event.key 来检查 Tab。在 Mozilla 开发者页面 上阅读相关信息。 - Fr0zenFyr

4

默认的选项卡行为是只前往下一个(按照源代码顺序)表单元素,因此您可以遍历所有您关注的元素,找到具有焦点的元素,并将焦点移动到下一个。我们有:input选择器来查找表单元素,因此可以使用以下代码:

var $all = $('form :input');
var focused = $(':focus')[0];
for(var i = 0; i < $all.length - 1; ++i) {
    if($all[i] != focused)
        continue;
    $all[i + 1].focus();
    break;
}
// Must have been focused on the last one or none of them.
if(i == $all.length - 1)
    $all[0].focus();

演示: http://jsfiddle.net/ambiguous/Avugy/1/

或者您可以设置tabindex属性并递增它们,实现循环:

var next_idx = parseInt($(':focus').attr('tabindex'), 10) + 1;
var $next_input = $('form [tabindex=' + next_idx + ']');
if($next_input.length)
    $next_input.focus();
else
    $('form [tabindex]:first').focus();

示例:http://jsfiddle.net/ambiguous/k9VpV/

处理tabindex属性值中的空缺留待练习。


1
谢谢,但我不喜欢你的方法。关于第一个,搜索我关心的所有元素是非常昂贵的(我有很多),而且不是动态的(不考虑我添加的新元素)。此外,我不知道我感兴趣的元素是什么。你的第二个方法有第一个的缺点,并且需要所有元素具有不同的tabindex... - Randomblue

0
$('input').first().focus();

var e = $.Event('keydown');

e.which = 9; // TAB
$(':focus').bind('keydown',function(e){
    if(e.which == 9){
        //this.value="tab";
        $('input:eq(1)').focus();
    }
   e.preventDefault(); 
});

你需要将 'keydown' 事件绑定到 并自定义你的事件函数。

谢谢。但是这个最终结果不是我想要的!我应该使用什么代码,以便将焦点放在由tabindex确定的下一个元素上? - Randomblue
这只是专注于第二个输入元素。这并不是tabIndex所规定的! - Randomblue
这不是对实际问题的答案,但谷歌把我带到了这里找到了我的答案,所以+1。 - electroid


0

这里有一个使用jQuery模拟Enter键的TAB功能的解决方案:

https://jsfiddle.net/tuho879j/

$('input').keypress(function(event){
  if(event.which == '13')   //ENTER     
  {
    var tabIndex = $(this).attr('tabIndex');

    var all_inputs = $(this).closest('table').find('input:visible');
    var inputs = all_inputs.filter(function() {
      return $(this).attr("tabIndex") > tabIndex;
    })

    if(inputs.length != 0)
    {
        inputs = $(inputs).sort(function(a,b){
          return $(a).attr('tabIndex')-$(b).attr('tabIndex');
        });
    }
    else
    {
        inputs = $(all_inputs).sort(function(a,b){
          return $(a).attr('tabIndex')-$(b).attr('tabIndex');
        });
    }


    var elem = inputs.eq( inputs.index(this)+ 1 );
    if(elem.length == 0)
        elem = inputs.eq(0);

    elem.focus();
    event.preventDefault();
  }
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接