将可聚焦控件限制为当前对话框的最佳方法是什么?

Sup*_*ova 5 html javascript css jquery

我有一个带对话框的Web应用程序.对话框是附加到正文的简单div容器.整个页面还有一个叠加层,以防止点击其他控件.但是:目前用户可以聚焦覆盖下的控件(例如输入).有没有办法将tabbable控件限制为对话框中的控件?

我正在使用jQuery(但现在是jQueryUI).在jQueryUI的对话框它的工作(但我希望使用jQueryUI的).我没弄明白,这是如何实现的.

以下是jQueryUI示例:http://jqueryui.com/resources/demos/dialog/modal-confirmation.html - 网页上的链接无法调整.焦点保留在对话框内(用户无法使用选项卡聚焦浏览器的urlbar).

HTML:

<a href="#test" onclick="alert('Oh no!');">I should not receive any focus</a>
<input type="text" value="No focus please" />
<div class="overlay">
    <div class="dialog">
        Here is my dialog<br />
        TAB out with Shift+Tab after focusing "focus #1"<br />
        <input type="text" value="focus #1" /><br />
        <input type="text" value="focus #1" /><br />
    </div>
</div>    
Run Code Online (Sandbox Code Playgroud)

CSS:

.overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0, 0, 0, 0.3);
    text-align: center;
}

.dialog {
    display: inline-block;
    margin-top: 30%;
    padding: 10px;
    outline: 1px solid black;
    background-color: #cccccc;
    text-align: left;
}
Run Code Online (Sandbox Code Playgroud)

这是我的小提琴:http://jsfiddle.net/SuperNova3000/weY4L/

有人有想法吗?我再说一遍:我不想为此使用jQueryUI.我想了解基础技术.

Sup*_*ova 5

经过几个小时的尝试,我找到了解决此问题的简单方法。我认为最好的方法是添加 2 个伪元素。一张在对话框之前,一张在对话框之后(在覆盖层内)。我使用的是 0x0 像素的 <a>-标签。当到达第一个 <a> 时,我将焦点集中在对话框中的最后一个控件。当聚焦最后一个 <a> 时,我将聚焦对话框中的第一个控件。

我改编了这篇文章的答案:Is there a jQuery selecter to get all elements that can get focus? - 找到第一个和最后一个可聚焦控件。

HTML:

<div class="overlay">
    <a href="#" class="focusKeeper">
    <div class="dialog">
        Here is my dialog<br />
        TAB out with Shift+Tab after focusing "focus #1"<br />
        <input type="text" value="focus #1" /><br />
        <input type="text" value="focus #1" /><br />
    </div>
    <a href="#" class="focusKeeper">
</div>    
Run Code Online (Sandbox Code Playgroud)

额外的CSS:

.focusKeeper {
    width: 0;
    height: 0;
    overflow: hidden;
}
Run Code Online (Sandbox Code Playgroud)

我的 JavaScript:

$.fn.getFocusableChilds = function() {
  return $(this)
    .find('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object:not([disabled]), embed, *[tabindex], *[contenteditable]')
    .filter(':visible');
};

[...]

$('.focusKeeper:first').on('focus', function(event) {
    event.preventDefault();
    $('.dialog').getFocusableChilds().filter(':last').focus();
});

$('.focusKeeper:last').on('focus', function(event) {
    event.preventDefault();
    $('.dialog').getFocusableChilds().filter(':first').focus();
});
Run Code Online (Sandbox Code Playgroud)

也许我稍后会添加一个小提琴,现在没有时间了。:(


编辑:正如 KingKing 在下面指出的那样,当单击控件外部时,焦点会丢失。这可以通过为 .overlay 添加 mousedown 处理程序来解决:

$('.overlay').on('mousedown', function(event) {
    event.preventDefault();
    event.stopImmediatePropagation();
});
Run Code Online (Sandbox Code Playgroud)

编辑#2:还缺少一件事:将焦点移到文档之外(例如标题栏),然后按 Tab 键返回。因此,我们需要另一个文档处理程序,它将焦点放回到第一个可聚焦元素上:

$(document).on('focus', function(event) {
    event.preventDefault();
    $('.dialog').getFocusableChilds().filter(':first').focus();
});
Run Code Online (Sandbox Code Playgroud)