防止标签通过地址栏循环



我意识到这可能是一个可访问性问题,最好不要管它,但我想弄清楚是否有可能在选项卡循环中防止选项卡访问地址栏。

我的应用程序有另一种循环输入区域的方法,但许多新用户本能地尝试使用选项卡,但它并没有像预期的那样工作。

这是一个通用的jquery实现,您不需要找到max标签索引。注意,如果在DOM中添加或删除元素,这段代码也可以工作。

$('body').on('keydown', function (e) {
    var jqTarget = $(e.target);
    if (e.keyCode == 9) {
        var jqVisibleInputs = $(':input:visible');
        var jqFirst = jqVisibleInputs.first();
        var jqLast = jqVisibleInputs.last();
        if (!e.shiftKey && jqTarget.is(jqLast)) {
            e.preventDefault();
            jqFirst.focus();
        } else if (e.shiftKey && jqTarget.is(jqFirst)) {
            e.preventDefault();
            jqLast.focus();
        }
    }
});
但是,您应该注意,上面的代码只适用于可见的输入。有些元素可能会成为文档的activeElement,即使它们不是输入,所以如果是你的情况,你应该考虑将它们添加到$(':input:visible')选择器中。

我没有添加代码滚动到焦点元素,因为这可能不是每个人都想要的行为…如果您需要它,只需在调用focus()后添加它

您可以使用全局tabindex属性控制选项卡顺序(以及哪些元素应该能够获得焦点)。

然而,你不能用这个属性阻止用户进入另一个不在页面控制之下的上下文(例如浏览器的地址栏)。(与JavaScript结合使用也可以)

对于这样一个(邪恶的)用例,您必须查看键盘陷阱

WCAG 2.0的指导原则是:2.1.2无键盘陷阱。在理解SC 2.1.2中,你可以找到这个指南的"技巧和失败":

  • F10:由于组合多种内容格式的方式将用户困在一种格式类型中,导致成功标准2.1.2和一致性要求5失败
  • FLASH17:为Flash对象提供键盘访问并避免键盘陷阱
  • G21:确保用户不被内容困住

所以也许你能从中得到一些想法,这样的陷阱是如何可能的。

我曾经在tabindex 1和最后一个tabindex上添加两个微小的、不可见的元素。为这两个元素添加onFocus: tabindex为1的元素应该关注最后一个真实元素,tabindex为max的元素应该关注第一个真实元素。确保将第一个真正的元素集中在Dom:loaded上。

您可以使用Javascript捕获具有最高"tabindex"的元素上的"keydown"事件。如果用户按"TAB"键(event. keycode ==9)而没有按"Shift"键(event. keycode ==9)。shiftKey == false),然后简单地将焦点设置在表索引最低的元素上。

您还需要对表索引最低的元素反向执行相同的操作。捕获该元素的"keydown"事件。如果用户按下"TAB"键(event. keycode ==9)与"Shift"键(event. keycode ==9)。shiftKey == true),然后将焦点设置在tabindex最高的元素上。

这将有效地防止使用TAB键聚焦地址栏。我在我目前的项目中使用了这种技术。

如果按了正确的组合键,不要忘记取消keydown事件!对于JQuery,它是"event.preventDefault()"。在标准Javascript中,我相信您只需"返回false"。

这是一个jquery加载的片段,我正在使用…

    $('#dos-area [tabindex=' + maxTabIndex + ']').on('keydown', function (e) {
        if (e.keyCode == 9 && e.shiftKey == false) {
            e.preventDefault();
            $('#dos-area [tabindex=1]').focus();
        }
    });
    $('#dos-area [tabindex=1]').on('keydown', function (e) {
        if (e.keyCode == 9 && e.shiftKey == true) {
            e.preventDefault();
            $('#dos-area [tabindex=' + maxTabIndex + ']').focus();
        }
    });

还要记住,设置tabindex=0会对事物集中的顺序产生不良影响。我总是记得(就我的目的而言)tabindex是一个基于1的索引。

嗨,我有一个简单的解决办法。只需在页面的末尾放置一个空白的跨距。给它一个id和tabindex = 0,给这个span一个onfocus事件,当触发时让你的焦点跳转到你想要循环的页面上的第一个元素。这样您就不会失去对文档的关注,因为如果您这样做,您的事件将不再工作。

我使用m-albert解决方案,它有效。但在我的情况下,我不控制tabindex属性。我的意图是在用户离开页面上的最后一个控件时,将焦点设置在页面顶部的工具栏(第一个控件)

$(':input:visible').last().on('keydown', function (e) {
    if (e.keyCode == 9 && e.shiftKey == false) {
        e.preventDefault();
        $('html, body').animate({
            scrollTop: 0
        }, 500);
        $(':input:visible', context).first().focus();
    }
});

其中context可以是任何Jquery对象,选择器,甚至文档,或者你可以省略它。

滚动动画,当然,是可选的

不确定这是否仍然是一个问题,但我实现了自己的解决方案,不使用jQuery,可以在所有元素都有tabindex="0"的情况下使用,并且当DOM可能发生变化时。如果希望将表循环限制为包含tabindex元素的特定元素,我为上下文添加了一个额外的参数。

关于参数的一些简短说明:

min必须小于或等于max,并且contextSelector是一个可选字符串,如果使用的话,它应该是一个有效的选择器。如果contextSelector是无效的选择器或选择器不匹配任何元素,则使用document对象作为上下文。

function PreventAddressBarTabCyle(min, max, contextSelector) {
    if( isNaN(min) ) throw new Error('Invalid argument: first argument needs to be a number type.')
    if( isNaN(max) ) throw new Error('Invalid argument: second argument needs to be a number type.')
    if( max < min ) throw new Error('Invalid arguments: first argument needs to be less than or equal to the second argument.')
    min = min |0;
    max = max |0;
    var isDocumentContext = typeof(contextSelector) != 'string' || contextSelector == '';
    if( min == max ) {
        var tabCycleListener = function(e) {
            if( e.keyCode != 9 ) return;
            var context = isDocumentContext ? document : document.querySelector(contextSelector);
            if( !context && !('querySelectorAll' in context) ) {
                context = document;
            }
            var tabindexElements = context.querySelectorAll('[tabindex]');
            if( tabindexElements.length <= 0 ) return;
            var targetIndex = -1;
            for(var i = 0; i < tabindexElements.length; i++) {
                if( e.target == tabindexElements[i] ) {
                    targetIndex = i;
                    break;
                }
            }
            // Check if tabbing backward and reached first element
            if( e.shiftKey == true && targetIndex == 0 ) {
                e.preventDefault();
                tabindexElements[tabindexElements.length-1].focus();
            }
            // Check if tabbing forward and reached last element
            if( e.shiftKey == false && targetIndex == tabindexElements.length-1 ) {
                e.preventDefault();
                tabindexElements[0].focus();
            }
        };
    } else {
        var tabCycleListener =  function(e) {
            if( e.keyCode != 9 ) return;
            var context = isDocumentContext ? document : document.querySelector(contextSelector);
            if( !context && !('querySelectorAll' in context) ) {
                context = document;
            }
            var tabindex = parseInt(e.target.getAttribute('tabindex'));
            if( isNaN(tabindex) ) return;
            // Check if tabbing backward and reached first element
            if (e.shiftKey == true && tabindex == min) {
                e.preventDefault();
                context.querySelector('[tabindex="' + max + '"]').focus();
            } 
            // Check if tabbing forward and reached last element
            else if (e.shiftKey == false && tabindex == max) {
                e.preventDefault();
                context.querySelector('[tabindex="' + min + '"]').focus();
            }
        };
    }
    document.body.addEventListener('keydown', tabCycleListener, true);
}

更指出:

如果min等于max,则制表符循环将自然进行,直到到达上下文中的最后一个元素。如果min严格小于max,则tab将自然循环,直到达到minmax。如果向后tab键到达min,或者向前tab键到达max,则tab键将分别循环到min元素或max元素。

使用例子:

// For all tabindex elements inside the document
PreventAddressBarTabCyle(0,0);
// Same as above
PreventAddressBarTabCyle(1,1);
// NOTE: if min == max, the tabindex value doesn't matter
//    it matches all elements with the tabindex attribute
// For all tabindex elements between 1 and 15
PreventAddressBarTabCyle(1,15);
// For tabindex elements between 1 and 15 inside
//   the first element that matches the selector: .some-form
PreventAddressBarTabCyle(1,15, '.some-form');
// For all tabindex elements inside the element
//   that matches the selector: .some-form2
PreventAddressBarTabCyle(1,1, '.some-form2');

Salinan解决方案对我有效把它放在html页面的开头:

<span tabindex="0" id="prevent-outside-tab"></span>

和这个在HTML页面的末尾。:

<span tabindex="0" onfocus="foucsFirstElement()"></span>

foucsFirstElement ():

foucsFirstElement() {
  document.getElementById("prevent-outside-tab").focus();
},

相关内容

  • 没有找到相关文章

最新更新