Проблема с dropdown

Рейтинг: 0Ответов: 2Опубликовано: 29.03.2023

При разработке дропдауна столкнулся со следующей проблемой. Идея в том, чтобы при клике на кнопку открывать дропдаун. Если дропдаун открыт, то при клике на любой элемент кроме его - закрывать дропдаун. Пишу код на чистом JS.

Вызов дропдауна.

<button class="header__btn header__services">услуги</button>

<ul class="header__submenu-1">
    <li class="header__subitem-1">
        <a href="#" class="header__item-link header__subitem-link">Проектирование</a>
    </li>
</ul>
let btnServices = document.querySelector('.header__services'),
    blockSubmenu1 = document.querySelector('.header__submenu-1');

btnServices.addEventListener('click', () => {
    blockSubmenu1.classList.add('header__submenu-1_active');
    setTimeout(hideSubmenu1, 400);
});

Закрытие дропдауна.

function hideSubmenu1(){
    document.body.addEventListener('click', (e) => {
        if(e.target !== blockSubmenu1) {
            blockSubmenu1.classList.remove('header__submenu-1_active');
        }
    });
}

При загрузке страницы и клике на кнопку btnServices дропдаун открывается. При клике на любое место закрывается, но не учитывается условие игноррирования закрытия при клике на blockSubmenu1. К тому же после выполнения данных действий повторно dropdown не открывается.

Ответы

▲ 0

Попробуйте вот такой способ:

let btnServices = document.querySelector('.header__services'),
  blockSubmenu1 = document.querySelector('.header__submenu-1'),
  submenuItem = document.querySelector('.header__subitem-1'),
  submenuLink = document.querySelector('.header__item-link');


function toggleDropduwn(e) {

  if (e.target === btnServices) {
    if (blockSubmenu1.classList.contains('header__submenu-1_active')) {
      blockSubmenu1.classList.remove('header__submenu-1_active');
      return;
    } else {
      blockSubmenu1.classList.add('header__submenu-1_active');
      return;
    }

  }
  if (e.target !== blockSubmenu1 && e.target !== submenuItem && e.target !== btnServices && e.target !== submenuLink) {
    blockSubmenu1.classList.remove('header__submenu-1_active');
  }
}


document.body.addEventListener('click', (e) => toggleDropduwn(e));
body {
  min-height: 100vh;
  margin: 0;
}

ul {
  background-color: lightgray;
  padding: 20px;
  list-style: none;
  display: none;
}

.header__submenu-1_active {
  display: block;
}
<button class="header__btn header__services">услуги</button>

<ul class="header__submenu-1">
  <li class="header__subitem-1">
    <a href="#" class="header__item-link header__subitem-link">Проектирование</a>
  </li>
</ul>

▲ 0

document.addEventListener('DOMContentLoaded', function() {
  let btnServices = document.querySelector('.header__services');
  let blockSubmenu1 = document.querySelector('.header__submenu-1');

  function toggleSubmenu1() {
    blockSubmenu1.classList.toggle('header__submenu-1_active');
  
    // отображаем элементы (для наглядности)
    blockSubmenu1.style.display = 'block'; 
   
    if (blockSubmenu1.classList.contains('header__submenu-1_active')) {
      document.addEventListener('click', hideSubmenu1);
    } else {
      document.removeEventListener('click', hideSubmenu1);
    }
  }

  function hideSubmenu1(e) {
    if (!blockSubmenu1.contains(e.target) && e.target !== btnServices) {
      blockSubmenu1.classList.remove('header__submenu-1_active');
      // Скрываем элементы (для наглядности)
      blockSubmenu1.style.display = 'none';
    
      document.removeEventListener('click', hideSubmenu1);
    }
  }

  btnServices.addEventListener('click', toggleSubmenu1);
});
<button class="header__btn header__services">услуги</button>

<ul class="header__submenu-1">
    <li class="header__subitem-1">
        <a href="#" class="header__item-link header__subitem-link">Проектирование</a>
    </li>
</ul>
<style>
.header__submenu-1{
    display: none;
}
.header__submenu-1_active {
    display: block;
}
</style>

Но я бы упростил код т.о.:

function toggleSubmenu1() {
  const btnServices = document.querySelector('.header__services');
  const blockSubmenu1 = document.querySelector('.header__submenu-1');
  const isActive = blockSubmenu1.classList.toggle('header__submenu-1_active');
  blockSubmenu1.style.display = isActive ? 'block' : 'none';
  if (isActive) {
    document.addEventListener('click', hideSubmenu1);
  } else {
    document.removeEventListener('click', hideSubmenu1);
  }
}

const hideSubmenu1 = (e) => {
  const btnServices = document.querySelector('.header__services');
  const blockSubmenu1 = document.querySelector('.header__submenu-1');
  if (!blockSubmenu1.contains(e.target) && e.target !== btnServices) {
    blockSubmenu1.classList.remove('header__submenu-1_active');
    blockSubmenu1.style.display = 'none';
    document.removeEventListener('click', hideSubmenu1);
  }
};

document.querySelector('.header__services').addEventListener('click', toggleSubmenu1);