Как закрыть подменю, когда мы фокусируемся на другом элементе в ванильном javascript

#javascript #html #sass

Вопрос:

Я новичок в Javascript и пытаюсь создать навигационную панель с подменю, используя ванильный Javascript. Я попытался настроить подменю на отображение / скрытие по щелчку, но я также хотел бы, чтобы подменю скрывалось, когда мы фокусируемся на другом элементе. Я пытался, но не могу этого сделать.

Вот мой код, если вы можете, пожалуйста, взгляните: HTML:

 <nav id="navigation" class="main-nav">
        <div class="wrapper">
            <a href="index.html" class="nav-logo">MAIN LOGO</a>
            <div id="sidebarNav" class="sidebar-nav">
                <button class="closeBtn" id="closeMenu">
                    <i class="bi bi-x"></i>
                </button>
                <ul class="menu">
                    <li class="menu-item"><a href="index.html" class="menu-link">Home</a></li>
                    <li class="menu-item"><a href="#" class="menu-link">About</a></li>
                    <li class="menu-item menu-item-has-children">
                        <a href="#" class="menu-link">
                            Dropdown
                        </a>
                        <ul class="sub-menu">
                            <li class="menu-item"><a href="#" class="menu-link">Home Grid</a></li>
                            <li class="menu-item"><a href="#" class="menu-link">Home Grid 3 col</a></li>
                            <li class="menu-item"><a href="#" class="menu-link">Home Grid 3 col Full</a></li>
                        </ul>
                    </li>
                    <li class="menu-item"><a href="#" class="menu-link">Contact</a></li>
                    <li class="menu-item"><a href="#" class="menu-link">Link</a></li><li class="menu-item menu-item-has-children">
                        <a href="#" class="menu-link">
                            Dropdown
                        </a>
                        <ul class="sub-menu">
                            <li class="menu-item"><a href="#" class="menu-link">Home Grid</a></li>
                            <li class="menu-item"><a href="#" class="menu-link">Home Grid 3 col</a></li>
                            <li class="menu-item"><a href="#" class="menu-link">Home Grid 3 col Full</a></li>
                        </ul>
                    </li>
                    <li class="menu-item"><a href="#" class="menu-link">Blog</a></li>
                </ul>
            </div>
            <button id="toggleSidebar" class="toggle-button">
                <i class="bi bi-list"></i>
            </button>
        </div><!-- .wrapper -->
    </nav>
 

CSS:

 .site-header {
width: 100%;
position: relative;
z-index: 999;

.toggle-button {
    border: 1px groove rgba(0, 0, 0, 0.1);
    padding: 3px 8px;
    margin: 8px 0;
    text-align: center;
    cursor: pointer;
    display: none;

    i {
        font-size: 22px;
    }
}

.main-nav {
    background: #ddd;

    .wrapper {
        display: flex;
        align-items: center;
        justify-content: space-between;

        .sidebar-nav {
            display: flex;
            align-items: center;
            justify-content: flex-end;
        }

        .menu {
            display: flex;
            align-items: center;
            justify-content: space-between;
            list-style: none;
            padding: 0;
            margin: 0;

            .menu-item {
                list-style: none;
                margin: 0;
                padding: 0;

                a {
                    padding: 20px 15px;
                    display: block;
                }
            }
        }

        .menu-item {

            amp;.menu-item-has-children {
                position: relative;

                .sub-menu {
                    position: absolute;
                    top: 100%;
                    left: 0;
                    padding: 0;
                    margin: 0;
                    text-align: left;
                    background: #fff;
                    border-top: 3px solid green;
                    min-width: 180px;
                    line-height: 1;
                    text-align: left;
                    z-index: 999;
                    box-shadow: 0 0 2px 1px rgba(0,0,0,0.2);
                    display: none;

                    li {
                        margin: 0;
                        padding: 0;
                        display: block;
                        border-bottom: 1px solid rgba(189, 188, 188, 0.3);

                        a {
                            font-size: .9rem;
                            font-weight: 400;
                            line-height: 1.2em;
                            letter-spacing: 0.6px;
                            padding: 15px;
                            text-transform: capitalize;
                            color: #555555;
                        }
                    }

                    
                }
            }

            amp;.active {
                .sub-menu {
                    display: block;
                }
            }
        }

        .menu-item-has-children > a::after {
            margin-left: .2rem;
            vertical-align: 0;
            border: none !important;
            content: "2193" !important;
            font: normal;
            font-size: 13px;
            font-weight: 900;
            color: #333;
        }
    }
}
 

}

JS:

 function dropdownMenu() {

const submenus = document.querySelectorAll(".menu-item-has-children");

for (var i = 0; i < submenus.length; i  ) {
    submenus[i].addEventListener("click", function (e) {
        e.preventDefault();
        e.stopPropagation();
        var last = this.closest('ul').querySelector('.active');
        if (last amp;amp; last !== this) last.classList.remove("active");
        this.classList.toggle("active");
    });
}

document.addEventListener("click", function () {
    var last = document.querySelector('.main-nav .active');
    if (last) last.classList.remove("active");
    if (last amp;amp; last ) last.classList.remove("active");
});
 

}
Выпадающее меню();

Ответ №1:

Попробуйте этот пример. Я добавил в ваш цикл for дополнительные addEventListener функции для mouseleave и очистил ненужные строки в файле js.

 function dropdownMenu() {
  const submenus = document.querySelectorAll('.menu-item-has-children');

  for (let i = 0; i < submenus.length; i  ) {
    submenus[i].addEventListener('click', function (e) {
      e.stopPropagation();
      const last = this.closest('ul').querySelector('.active');
      if (last amp;amp; last !== this) last.classList.remove('active');
      this.classList.toggle('active');
    });

    // Added lines
    submenus[i].addEventListener('focusout', function () {
      const last = document.querySelector('.main-nav .active');
      if (last) last.classList.remove('active');
    });
   //===
  }
}

dropdownMenu(); 
 .site-header {
  width: 100%;
  position: relative;
  z-index: 999;
}
.toggle-button {
  border: 1px groove rgba(0, 0, 0, 0.1);
  padding: 3px 8px;
  margin: 8px 0;
  text-align: center;
  cursor: pointer;
  display: none;
}
.toggle-button i {
  font-size: 22px;
}

.main-nav {
  background: #ddd;
}
.wrapper {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.sidebar-nav {
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

.menu {
  display: flex;
  align-items: center;
  justify-content: space-between;
  list-style: none;
  padding: 0;
  margin: 0;
}
.menu-item {
  list-style: none;
  margin: 0;
  padding: 0;
}
.menu-item a {
  padding: 20px 15px;
  display: block;
}

.menu-item.menu-item-has-children {
  position: relative;
}
.sub-menu {
  position: absolute;
  top: 100%;
  left: 0;
  padding: 0;
  margin: 0;
  text-align: left;
  background: #fff;
  border-top: 3px solid green;
  min-width: 180px;
  line-height: 1;
  text-align: left;
  z-index: 999;
  box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.2);
  display: none;
}
.sub-menu li {
  margin: 0;
  padding: 0;
  display: block;
  border-bottom: 1px solid rgba(189, 188, 188, 0.3);
}
.sub-menu a {
  font-size: 0.9rem;
  font-weight: 400;
  line-height: 1.2em;
  letter-spacing: 0.6px;
  padding: 15px;
  text-transform: capitalize;
  color: #555555;
}

.menu-item-has-children.active .sub-menu {
  display: block;
}

.menu-item-has-children > a::after {
  margin-left: 0.2rem;
  vertical-align: 0;
  border: none !important;
  content: '2193' !important;
  font: normal;
  font-size: 13px;
  font-weight: 900;
  color: #333;
} 
 <nav id="navigation" class="main-nav">
      <div class="wrapper">
        <a href="index.html" class="nav-logo">MAIN LOGO</a>
        <div id="sidebarNav" class="sidebar-nav">
          <button class="closeBtn" id="closeMenu">
            <i class="bi bi-x"></i>
          </button>
          <ul class="menu">
            <li class="menu-item">
              <a href="index.html" class="menu-link">Home</a>
            </li>
            <li class="menu-item"><a href="#" class="menu-link">About</a></li>
            <li class="menu-item menu-item-has-children">
              <a href="#" class="menu-link"> Dropdown </a>
              <ul class="sub-menu">
                <li class="menu-item">
                  <a href="#" class="menu-link">Home Grid</a>
                </li>
                <li class="menu-item">
                  <a href="#" class="menu-link">Home Grid 3 col</a>
                </li>
                <li class="menu-item">
                  <a href="#" class="menu-link">Home Grid 3 col Full</a>
                </li>
              </ul>
            </li>
            <li class="menu-item"><a href="#" class="menu-link">Contact</a></li>
            <li class="menu-item"><a href="#" class="menu-link">Link</a></li>
            <li class="menu-item menu-item-has-children">
              <a href="#" class="menu-link"> Dropdown </a>
              <ul class="sub-menu">
                <li class="menu-item">
                  <a href="#" class="menu-link">Home Grid</a>
                </li>
                <li class="menu-item">
                  <a href="#" class="menu-link">Home Grid 3 col</a>
                </li>
                <li class="menu-item">
                  <a href="#" class="menu-link">Home Grid 3 col Full</a>
                </li>
              </ul>
            </li>
            <li class="menu-item"><a href="#" class="menu-link">Blog</a></li>
          </ul>
        </div>
        <button id="toggleSidebar" class="toggle-button">
          <i class="bi bi-list"></i>
        </button>
      </div>
    </nav> 

Комментарии:

1. Mouseleave закрывает подменю при событии мыши. Но, исходя из вашей идеи, я попытался использовать дочерние элементы, и это сработало. Проверьте код ниже. Надеюсь, я прав. var submenuList = submenus[i].querySelector(".sub-menu"); submenuList.lastElementChild.addEventListener('focusout', function () { const last = document.querySelector('.main-nav .active'); if (last) last.classList.remove('active'); }); Спасибо @ЖнецЪ

2. Да, вы можете использовать focusout для потери фокуса элемента. Я обновил обзор кода и очистил js.