如何使用javascript/jquery在特定div中锁定焦点

如何使用javascript/jquery在特定div中锁定焦点,javascript,jquery,Javascript,Jquery,我正在使用jQuery开发某种模式弹出窗口,但我在焦点方面遇到了一些问题 现在发生的是,当我按下tab键时,焦点转到隐藏在弹出窗口后面的控件 是否有办法强制焦点仅保留在弹出窗口中的控件上?有。您基本上需要在按下tab键时监听,以便做出相应的响应。使用jQuery,以下是一般结构: $(window).keydown(function(e){ if(e.which ===9){ //it's the tab key! //do whatever you want here.

我正在使用jQuery开发某种模式弹出窗口,但我在焦点方面遇到了一些问题

现在发生的是,当我按下tab键时,焦点转到隐藏在弹出窗口后面的控件


是否有办法强制焦点仅保留在弹出窗口中的控件上?

有。您基本上需要在按下tab键时监听,以便做出相应的响应。使用jQuery,以下是一般结构:

$(window).keydown(function(e){
    if(e.which ===9){ //it's the tab key!
        //do whatever you want here.

        e.preventDefault();
    }
});

您将自定义代码放在我注释的
位置,在此处执行任何您想执行的操作
,最后使用
e.preventDefault
阻止默认操作(例如将焦点跳到隐藏控件)

您可以随时查看如何删除
选项卡
键的默认操作,这里有一个关于如何执行此操作的小教程

但是,这是针对
enter
tab
键的,但是如果您同时查看,您将看到
tab
键是键号9。因此,如果我们修改代码,只删除
选项卡
键的默认操作,您的代码行将类似于

    if ( key == 9 ) { }
而不是

    if ( key == 3 || key == 9 || key == 13 ) { }
编辑

好的,既然您已经声明不希望阻止
选项卡
键的默认操作,但是您仍然希望阻止该键聚焦于模态窗口下方的元素

我现在唯一能想到的是,检查用户是否关注您的最后一个字段/(您可以将这些链接到您的最后一个输入/文本区域/复选框/收音机)。如果是这样,您可以做以下两件事中的一件:

1) 使用上面的代码并阻止默认操作,从而停止将焦点放在模态下面的元素上

2) 使用
first_field.Focus(),将焦点放回到模式窗口中的第一个字段上


据我所知,坚持你的要求,第二选择是你最好的选择。

试试看。只需防止用户按tab键,否则您将不得不在字段中循环并设置选项卡索引。

最后,我提出了以下解决方案:

当窗口打开时,我在jQuery.data内保存弹出窗口中没有的所有元素的tabindex,并将焦点设置为窗口的第一个元素

然后,对于所有这些元素,我将tabindex设置为-1,以防止使用tab键访问它们


当窗口关闭时,我将所有TabIndex恢复为其以前的值。

我使用添加到所有输入标记的通用聚焦事件,当事件被触发时,我确定父div的z索引,如果它高于预先确定的阈值(例如9950),然后我允许聚焦,如果低于我阻止聚焦。为了防止焦点,我在适当的div中找到一个控件并对该项调用.focus()

下面是伪代码

$('input').bind('focus', function() 
{ 
 if ($(this).parents('div:first').css('z-index') <  9950) 
 {
    //prevent focus here
    //usually by finding a suitable target and setting focus
   $('input:first', $('.myModalClass')).focus(); 
 }
}); 
$('input').bind('focus',function()
{ 
if($(this).parents('div:first').css('z-index')<9950)
{
//在这里防止焦点
//通常通过找到合适的目标和设定焦点
$('input:first',$('.myModalClass')).focus();
}
}); 

另外,还要在项目上设置tabindex,以便“模式”窗口中的项目在选项卡索引中紧跟其后。只是让事情变得更干净一点

我遇到了类似的问题,并创建了这个小小的jQUeryUI插件。简单地使用它(如果需要,可以在页面上的多个位置使用),这将使TAB或shift+TAB仅在.someGroup包装器中迭代

$(“.someGroup”).tabGuard()

这里有更多,我希望它能帮助一些人:


我想我可能有一个更好的解决方案来解决您的问题,它不需要禁用选项卡或跟踪/禁用其他元素。但它确实需要jQueryUI

<div id="modalBgCover">
    <div onfocus="$(this).next('div').find(':tabbable').last().focus();" tabindex="0"></div>
    <div id="modal">
        <input id="input1">
        <input id="input2">
    </div>
    <div onfocus="$(this).prev('div').find(':tabbable').first().focus();" tabindex="0"></div>
<div>

这样做的目的是创建两个tabbable(但没有内容,所以不可见)div,用于获取和重定向焦点

切换最后一个输入并切换到下一个div将使焦点返回到模态中的第一个tabbable元素,同样,shift+切换到上一个div将使焦点返回到模态中的下一个输入


modalBgCover用半透明层覆盖页面,防止点击通过。

我已经实现了基于收集知识(包括本文中的答案)的迷你框架

它使用jqueryui

欢迎改进

以下是框架对象:

var TabLim = {};

TabLim.activate = function(el) {
    TabLim.deactivate();

    TabLim._el = el;

    $(window).on('keydown', TabLim._handleTab);

    return TabLim;
};

TabLim.deactivate = function() {
    TabLim._el = null;

    // detach old focus events
    TabLim._detachFocusHandlers();

    TabLim._els = null;
    TabLim._currEl = null;

    $(window).off('keydown', TabLim._handleTab);

    return TabLim;
};

TabLim.setFocus = function(prev) {
    // detach old focus events
    TabLim._detachFocusHandlers();

    // scan for new tabbable elements
    var tabbables = TabLim._el.find(':tabbable');
    TabLim._els = [];

    // wrap elements in jquery
    for ( var i = 0; i < tabbables.length; i++) {
        var el = $(tabbables[i]);
        // set focus listener on each element
        el.on('focusin', TabLim._focusHandler);
        TabLim._els.push(el);
    }

    // determine the index of focused element so we will know who is
    // next/previous to be focused
    var currIdx = 0;
    for ( var i = 0; i < TabLim._els.length; i++) {
        var el = TabLim._els[i];

        // if focus is set already on some element
        if (TabLim._currEl) {
            if (TabLim._currEl === el[0]) {
                currIdx = i;

                prev ? currIdx-- : currIdx++;
                break;
            }

        } else {
            // focus is not set yet.
            // let's set it by attribute "autofocus".
            if (el.attr('autofocus') !== undefined) {
                currIdx = i;
                break;
            }
        }
    }

    if (currIdx < 0) {
        currIdx += TabLim._els.length;
    }
    if (TabLim._els.length) {
        TabLim._els[Math.abs(currIdx % TabLim._els.length)].focus();
    }

    return TabLim;
};

TabLim._handleTab = function(e) {
    if (e.which === 9) {
        e.preventDefault();

        TabLim.setFocus(e.shiftKey);
    }
};

TabLim._focusHandler = function(e) {
    TabLim._currEl = e.currentTarget;
};

TabLim._detachFocusHandlers = function() {
    if (TabLim._els) {
        for ( var i = 0; i < TabLim._els.length; i++) {
            TabLim._els[i].off('focusin', TabLim._focusHandler);
        }
    }
};
2) 停用

TabLim.deactivate();

当您打开模式弹出窗口时,如果您试图在最初按下“tab”键时将焦点放在第一个输入上,那么一个非常简单的解决方案是将焦点放在模式弹出窗口中的第一个输入上,然后简单地对该输入应用.blur()。然后,当你点击“tab”时,它将开始关注该表单

$("#modalTestInput").focus();
$("#modalTestInput").blur();
如果您试图删除任何关注模式弹出窗口后面输入的功能,那么您将
tabindex=“-1”
应用于模式弹出窗口之外输入的解决方案肯定是可行的


我想您可能会对一个更简单的解决方案感兴趣。

您可以在弹出窗口的任何控件中放置类似于
onblur=“this.focus()”
的内容,尽管这会将焦点锁定在当前选择的任何控件中。需要更多的代码来确定是否允许任何获得焦点的东西获得焦点。但是,谢谢,这对我来说不起作用,因为我必须遵守WCAG 2.0 AA指南,所有控件都应该可以使用键盘访问。那么你就自相矛盾了。“不允许访问控件,但所有控件都必须可访问”。我希望在打开窗口时将焦点包含在弹出窗口内。当窗口关闭时,应该可以使用键盘访问其他控件。那么它是否是一个实际的弹出窗口,就像在新的浏览器窗口中一样?还是仍然包含jQuery模式弹出窗口
$("#modalTestInput").focus();
$("#modalTestInput").blur();