我有一个带对话框的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>
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;
}
这是我的小提琴:http://jsfiddle.net/SuperNova3000/weY4L/
有人有想法吗?我再说一遍:我不想为此使用jQueryUI。我想了解基本技术。
答案 0 :(得分:4)
经过数小时的努力,我找到了解决这个问题的简单方法。我认为最好的方法是添加2个伪元素。对话框之前和之后(在叠加层内)。我使用&lt; a&gt; -Tags是0x0像素。当到达第一个&lt; a&gt;时,我将最后一个控件聚焦在对话框中。当聚焦最后一个&lt; a&gt;时,我将第一个控件聚焦在对话框中。
我已经调整了这篇文章的答案:Is there a jQuery selector 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>
额外的CSS:
.focusKeeper {
width: 0;
height: 0;
overflow: hidden;
}
我的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();
});
可能是我以后添加一个小提琴,暂时不再有时间。 :(
编辑:正如KingKing在下面指出的那样,当在控件外面点击时,焦点会丢失。这可以通过为.overlay添加一个mousedown处理程序来实现:
$('.overlay').on('mousedown', function(event) {
event.preventDefault();
event.stopImmediatePropagation();
});
编辑#2:还有另外一件事:用焦点(例如标题栏)走出文档,然后回到标签。所以我们需要另一个文档处理程序,它将焦点放在第一个可聚焦元素上:
$(document).on('focus', function(event) {
event.preventDefault();
$('.dialog').getFocusableChilds().filter(':first').focus();
});
答案 1 :(得分:2)
您可以尝试处理focusout
元素的.dialog
事件,查看e.target
。关于此处e.relatedTarget
的注释,它指的是获得焦点的元素,而e.target
指的是元素丢失焦点:
var tabbingForward = true;
//The body should have at least 2 input fields outside of the dialog to trap focusing,
//otherwise focusing may be outside of the document
//and we will loss control in such a case.
//So we create 2 dummy text fields with width = 0 (or opacity = 0)
var dummy = "<input style='width:0; opacity:0'/>";
var clickedOutside = false;
$('body').append(dummy).prepend(dummy);
$('.dialog').focusout(function(e){
if(clickedOutside) {
e.target.focus();
clickedOutside = false;
}
else if(!e.relatedTarget||!$('.dialog').has(e.relatedTarget).length) {
var inputs = $('.dialog :input');
var input = tabbingForward ? inputs.first() : inputs.last();
input.focus();
}
});
$('.dialog').keydown(function(e){
if(e.which == 9) {
tabbingForward = !e.shiftKey;
}
});
$('body').mousedown(function(e){
if(!$('.dialog').has(e.target).length) {
clickedOutside = true;
}
});