Javascript 确定焦点何时出现在元素外部

Javascript 确定焦点何时出现在元素外部,javascript,jquery,html,css,Javascript,Jquery,Html,Css,我想看看是否有以下可能: 由于性能原因,确定焦点是否在不使用文档级全局选择器(如$(文档)、$(正文)、$(窗口)等)的情况下发生在元素外部 如果没有全局选择器无法实现,请用可证明的理由解释自己。重要的是,我要理解为什么在当今的最新技术下这是不可行的 奖励回合:确定任务的最有效(计算时间方面)选择器/事件处理程序/插件 由一个非常简单的HTML导航栏组成,如下面的代码片段所示。我在每个之间进行本机键盘导航对于这个问题的范围来说是一种危险的技术,但是如果使用上述技术会产生最有效的方法,那么我会

我想看看是否有以下可能:

  • 由于性能原因,确定焦点是否在不使用文档级全局选择器(如
    $(文档)
    $(正文)
    $(窗口)
    等)的情况下发生在元素外部
  • 如果没有全局选择器无法实现,请用可证明的理由解释自己。重要的是,我要理解为什么在当今的最新技术下这是不可行的
  • 奖励回合:确定任务的最有效(计算时间方面)选择器/事件处理程序/插件

由一个非常简单的HTML导航栏组成,如下面的代码片段所示。我在每个
之间进行本机键盘导航对于这个问题的范围来说是一种危险的技术,但是如果使用上述技术会产生最有效的方法,那么我会欢迎它。

我不确定我是否100%遵循了这个问题,但我想我明白了

您可以使用
focusin
事件将
event.target
closest
一起使用

$(document).on('focusin', function (event) {
  var $target = $(event.target);
  if (!$target.closest('.bar').length) {
    console.log('You focused outside of .bar!');
  }
});

这里有一个难题:

这里的一个选项,没有全局选择器,是短暂延迟关闭操作:

  var isVisible = false;

  $(".test").focusin(function() {
    if (dropdownMenu.is(":hidden")) {
      dropdownMenu.show();
    }
    isFocused = true;
  });

  $(".test").focusout(function() {
    isFocused = false;
    setTimeout(function() {
      if (!isFocused && dropdownMenu.is(":visible")) {
        dropdownMenu.hide();
      }
    }, 100);
  });

这有点烦琐,但可以在切换时防止错误关闭。请参见

也许这是一种过于简单的方法,但解决方案不是基于
blur
事件执行某些检查吗?也许是检查是否有任何外部元素仍然集中(或者有一个内部元素),而不是检查整个文档?@GregL这就是我的困境所在,如果不是全局的,我应该寻找什么样的选择器?我尝试了
$(document.activeElement)
,它正确地侦听当前活动元素,但在哪个事件处理程序下?使用
blur
时,它会弄乱代码段中当前存在的显示/隐藏函数。试试看这是否能在Chrome中正常工作,否则我会错过你的意图。我看到,当我用tab键遍历所有条目,然后用tab键退出时,下拉菜单消失,但“Title”元素仍然可见。@nrabinowitz OP所说的问题只有在你取消对小提琴中的
focusout
处理程序的注释时才会发生。当我在Chrome中取消对这些行的注释时,我用tab键一次,它就会打开子菜单,我再次单击tab,子菜单消失。这不是OP想要的。我喜欢这个想法,但是我的挑战是避免使用全局选择器,例如
$(document)
,因为性能原因。我知道如果不使用全局选择器,这就不那么简单了,这就是为什么我也想知道是否可以在没有全局选择器的情况下完成,或者您可以将代码与任何其他选择器一起使用,它仍然可以工作。但我不确定这会如何导致性能问题。@Jason说得对(duh片刻),在这种情况下,我可以使用
x
而不是
$(文档)
每次搜索和侦听元素时都不会导致性能变化?但这不是性能问题-性能问题是页面上的每个
focusin
事件都会经过此处理程序,并且此处理程序每次都会执行一次可能昂贵的DOM查找,以查看我们是否在相关元素上。性能问题肯定是可能的,不过如果页面的其余部分不是性能密集型的,这可能无关紧要。您可以使用任何选择器。你似乎过早地优化了这里。我能看到您遇到性能问题的唯一方法是每秒聚焦1000次,并且输入像500个元素一样嵌套在一个可能的
.bar
中。这里它只是使用
input
作为选择器,不过:我喜欢它,我注意到
focusout
确实阻碍了焦点事件之间发生的事情,我从来没有想到过我应该使用超时功能,非常好!明天我将在我的现场网站上尝试这个,并随时向您发布消息。你认为你的答案与比尔的相比如何?我的意思是在评论中,他添加了一个非常简洁的JSFIDLE示例。我还对最佳性能方法(尽可能少)感兴趣。这在我的实时实现中非常有效,我很高兴您和其他所有人都在努力找出一种(稍微?)比使用更全局的选择器(如
$(document)
)更好的方法。荣誉如果你真的关心性能,我打赌
是(“:隐藏的”)
是(“:显示的”)
检查实际上是这里最昂贵的部分-只要调用
show
hide
,在错误的情况下它将是不起作用的。但我认为性能在这两种情况下都不应该是一个大问题,除非你有一个性能密集型应用程序(例如,在这个动作中出现的动画),这就证明了简单的代码优于高性能。这很有趣,我没想到
is()
hide()
show()
更昂贵。顺便说一句,我也不认为对性能的影响有什么大不了的,但在我这方面,我的手是被迫的,这一点也不坏,而且这使它成为一个更令人信服的问题。
is
不一定昂贵,但它必须根据元素评估选择器,和
:visible
:hidden
是昂贵的选择器(非本机)。
$(document).on('focusin', function (event) {
  var $target = $(event.target);
  if (!$target.closest('.bar').length) {
    console.log('You focused outside of .bar!');
  }
});
  var isVisible = false;

  $(".test").focusin(function() {
    if (dropdownMenu.is(":hidden")) {
      dropdownMenu.show();
    }
    isFocused = true;
  });

  $(".test").focusout(function() {
    isFocused = false;
    setTimeout(function() {
      if (!isFocused && dropdownMenu.is(":visible")) {
        dropdownMenu.hide();
      }
    }, 100);
  });