Javascript 当某个元素或其中任何元素';s的子代失去焦点,请删除一个类

Javascript 当某个元素或其中任何元素';s的子代失去焦点,请删除一个类,javascript,jquery,Javascript,Jquery,我试图让我的导航系统更容易使用,但我很难找出其中的一部分。这是我想要的功能列表 可通过键盘导航。这很好用 在子菜单前的按钮上单击/按enter键可切换其活动状态。这很好用 当子菜单或其任何子菜单失去焦点时,关闭子菜单。这就是我遇到麻烦的地方 问题是,我似乎无法准确判断元素或其子元素是否具有焦点。第一次按下“键盘”上的“tab”键时,它可以正常工作,但当它突出显示子列表中的第二个元素后,菜单关闭 下面是我所有的JS以及一些CSS和HTML示例 JS: CSS: HTML: 切换菜单

我试图让我的导航系统更容易使用,但我很难找出其中的一部分。这是我想要的功能列表

  • 可通过键盘导航。这很好用
  • 在子菜单前的按钮上单击/按enter键可切换其活动状态。这很好用
  • 当子菜单或其任何子菜单失去焦点时,关闭子菜单。这就是我遇到麻烦的地方
问题是,我似乎无法准确判断元素或其子元素是否具有焦点。第一次按下“键盘”上的“tab”键时,它可以正常工作,但当它突出显示子列表中的第二个元素后,菜单关闭

下面是我所有的JS以及一些CSS和HTML示例

JS:

CSS:

HTML:

  • 切换菜单
.
理想情况下,我希望用普通JavaScript而不是jQuery来完成这一切,但我想,一旦核心概念开始工作,我可以稍后再回去重构。

非常简单,这就是你可以做到的:

另外,将事件侦听器连接到
.menu list
并将
blur
事件从
.menu-list\u link
委托给它,这样您就不会有很多事件侦听器

jQuery(".menu-list").on("blur", ".menu-list_link", function(e) {
  var tThis = jQuery(this);
  var tThisParent = tThis.closest('.menu-list_item');
  var tThisGrandParent = tThisParent.closest('.menu-list');
  var tThisGreatGrandParent = tThisGrandParent.closest('.menu-list_item');
  if (tThisParent.is(':last-child')) {
    tThisGrandParent.attr("aria-hidden", "true");
    tThisGreatGrandParent.removeClass("is-active");
  }
});
仅当失去焦点的项目是其相应子菜单上的最后一个项目时,它才会关闭子菜单

演示:


此外,如果将整个菜单放在一个容器中,则可以将事件侦听器附加到该容器,而不是
.menu list
s,例如
.menu容器
,因此,对于该容器,DOM元素上只有一个事件侦听器

jQuery(".menu-container").on("blur", ".menu-list_link", function() {
  var tThis = jQuery(this);
  var tThisParent = tThis.closest('.menu-list_item');
  var tThisGrandParent = tThisParent.closest('.menu-list');
  var tThisGreatGrandParent = tThisGrandParent.closest('.menu-list_item');
  if (tThisParent.is(':last-child')) {
    tThisGrandParent.attr("aria-hidden", "true");
    tThisGreatGrandParent.removeClass("is-active");
  }
});
演示2:


还有一个小小的改进,如果失去焦点的项目是最外层的子菜单,不要隐藏菜单列表,这样最外层的菜单就保持可见

jQuery(".menu-container").on("blur", ".menu-list_link", function() {
  var tThis = jQuery(this);
  var tThisParent = tThis.closest('.menu-list_item');
  var tThisGrandParent = tThisParent.closest('.menu-list');
  var tThisGreatGrandParent = tThisGrandParent.closest('.menu-list_item');
  if (tThisParent.is(':last-child')) {
    if(!tThisGrandParent.is('.menu-container > .menu-list')) {
        tThisGrandParent.attr("aria-hidden", "true");
    }
    tThisGreatGrandParent.removeClass("is-active");
  }
});

演示3:

通常,如果发生
聚焦事件,我必须排队等待
聚焦出
更改并取消它们。非常好,谢谢!我想我知道这里发生了什么。有一件事,当你点击离开容器(而不是点击离开),它仍然保持打开状态。我会看一看,看看我是否能自己解决这个问题,但我想我也会让你知道的。
jQuery(".menu-list").on("blur", ".menu-list_link", function(e) {
  var tThis = jQuery(this);
  var tThisParent = tThis.closest('.menu-list_item');
  var tThisGrandParent = tThisParent.closest('.menu-list');
  var tThisGreatGrandParent = tThisGrandParent.closest('.menu-list_item');
  if (tThisParent.is(':last-child')) {
    tThisGrandParent.attr("aria-hidden", "true");
    tThisGreatGrandParent.removeClass("is-active");
  }
});
jQuery(".menu-container").on("blur", ".menu-list_link", function() {
  var tThis = jQuery(this);
  var tThisParent = tThis.closest('.menu-list_item');
  var tThisGrandParent = tThisParent.closest('.menu-list');
  var tThisGreatGrandParent = tThisGrandParent.closest('.menu-list_item');
  if (tThisParent.is(':last-child')) {
    tThisGrandParent.attr("aria-hidden", "true");
    tThisGreatGrandParent.removeClass("is-active");
  }
});
jQuery(".menu-container").on("blur", ".menu-list_link", function() {
  var tThis = jQuery(this);
  var tThisParent = tThis.closest('.menu-list_item');
  var tThisGrandParent = tThisParent.closest('.menu-list');
  var tThisGreatGrandParent = tThisGrandParent.closest('.menu-list_item');
  if (tThisParent.is(':last-child')) {
    if(!tThisGrandParent.is('.menu-container > .menu-list')) {
        tThisGrandParent.attr("aria-hidden", "true");
    }
    tThisGreatGrandParent.removeClass("is-active");
  }
});