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

Javascript 什么';将可聚焦控件限制为当前对话框的最佳方法是什么?,javascript,jquery,html,css,Javascript,Jquery,Html,Css,我有一个带有对话框的web应用程序。对话框是附加到主体的简单div容器。还有一个覆盖整个页面,以防止点击其他控件。但是:目前用户可以聚焦覆盖下的控件(例如输入)。有没有办法将选项卡控件限制为对话框中的控件 我使用的是jQuery(但不是jQueryUI)。在jQueryUi对话框中,它正在工作(但我不想使用jQueryUi)。我没能弄明白,这是怎么做到的 以下是jQueryUI示例:-网页上的链接不可聚焦。焦点保持在对话框内(用户不能使用tab键聚焦浏览器的urlbar) HTML: 这是我的小

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

我使用的是jQuery(但不是jQueryUI)。在jQueryUi对话框中,它正在工作(但我不想使用jQueryUi)。我没能弄明白,这是怎么做到的

以下是jQueryUI示例:-网页上的链接不可聚焦。焦点保持在对话框内(用户不能使用tab键聚焦浏览器的urlbar)

HTML:

这是我的小提琴:


有人有主意吗?我再说一遍:我不想用jQueryUI来做这个。我想了解基本技术。

您可以尝试处理
对话框
元素的
聚焦输出
事件,检查
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;        
  }
});
var tabbingfroward=true;
//主体应在对话框外至少有2个输入字段以捕捉聚焦,
//否则,聚焦可能在文档之外
//在这种情况下,我们将失去控制。
//因此,我们创建了两个宽度为0(或不透明度为0)的虚拟文本字段
var虚拟=”;
var clickedOutside=false;
$('body').append(dummy).prepend(dummy);
$('.dialog').focusout(函数(e){
如果(单击外侧){
e、 target.focus();
单击外侧=false;
}
如果(!e.relatedTarget | |!$('.dialog').has(e.relatedTarget).length){
变量输入=$('对话框:输入');
var input=tabbingfroward?inputs.first():inputs.last();
input.focus();
}
}); 
$('.dialog').keydown(函数(e){
如果(e.which==9){
tabbingForward=!e.shiftKey;
}
});
$('body').mousedown(函数(e){
如果(!$('.dialog').has(e.target.length){
单击外侧=真;
}
});

经过几个小时的尝试,我找到了解决这个问题的简单方法。我认为最好的方法是添加2个伪元素。一个在对话框之前,一个在对话框之后(覆盖层内部)。我正在使用-查找第一个和最后一个可聚焦控件

HTML:

我的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').on('mousedown', function(event) {
    event.preventDefault();
    event.stopImmediatePropagation();
});

编辑#2:缺少另一件事:使用焦点(例如标题栏)跳出文档,然后使用制表符返回。因此,我们需要另一个文档处理程序将焦点放回第一个可聚焦元素:

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

很抱歉,但使用TAB我可以将注意力集中在链接和文本字段上。嗯,这很有意义。但它与我上面发布的jQueryUI演示相去甚远。我认为缺少了一些东西(@SuperNova看起来不是一个容易解决的问题,我们甚至需要使用虚拟技术,试试我更新的演示,看看它现在是否有效。@KingKing:我真的很感谢你的帮助。我刚刚看到你尝试了我知道的同样的技术。但是我认为我的事件侦听器更容易维护和理解。我希望没问题,wh是否将我自己的答案标记为已接受的答案?@SuperNova是的,对于某些人来说,这种处理事件的方式可能很容易理解,但是如果您在对话框外单击,则当前关注的元素(不是
:first
:last
)将失去焦点,如果这种行为是好的,你可以用你自己的方式,当然接受你自己的答案是可以的,如果这正是你想要的(将其视为最佳答案)。顺便说一句,根据你发布的代码,我不确定它是否有效,只需自己创建演示。注意jQueryUI有“:tabbable”选择器,用于选择所有此类元素。这是真的。但它仅在使用jqueryui时才起作用。我不会包含整个库,以使用:tabbable选择器。但我认为最好查看它们的源代码(可能是我遗漏了一个tabbable元素)@SuperNove,我知道你的意思。我为其他可能已经在使用jQuery UI的人添加了评论。我正要发帖说这不起作用,但我把
.focuskeeper
链接放在了对话框分区内。在这上面浪费了一个小时。哦!无论如何,效果很好
.focusKeeper {
    width: 0;
    height: 0;
    overflow: hidden;
}
$.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();
});
$('.overlay').on('mousedown', function(event) {
    event.preventDefault();
    event.stopImmediatePropagation();
});
$(document).on('focus', function(event) {
    event.preventDefault();
    $('.dialog').getFocusableChilds().filter(':first').focus();
});