Как сделать открытие/закрытие подменю по клику не запрещая всплытие?

116
17 сентября 2021, 21:50

Имеется выпадающее подменю. Открывается по клику на второй пункт меню, закрывается по клику на него же, либо на любое пространство, кроме самого выпавшего подменю. Чтобы подменю закрывалось по клику вне его, пришлось запретить всплытие при его открытии, иначе оно открывалось и мгновенно закрывалось. Можно ли как то это реализовать не запрещая всплытие?

let subMenuShow = document.querySelector('.menu li:nth-child(2)'); 
let subMenu = document.querySelector('.sub-menu'); 
 
// Открыть подменю 
let SwitchMenu = function() { 
  subMenu.classList.toggle('open'); 
  event.stopPropagation(); 
}; 
 
subMenuShow.addEventListener("click", SwitchMenu); 
 
 
// Закрыть подменю 
function menuClose() { 
  subMenu.classList.remove('open'); 
} 
 
function menuCloseClickOutside(e) { 
  if (!e.target.matches('.sub-menu, .sub-menu *')) { 
    menuClose(); 
  }; 
}; 
 
document.addEventListener('click', menuCloseClickOutside); 
document.addEventListener('touchstart', menuCloseClickOutside);

Answer 1

Непонятно, зачем вообще хардкодить индекс элемента меню.

Можно решить задачу очень просто, и относительно гибко:

document.addEventListener('DOMContentLoaded', () => { 
  document.body.addEventListener('click', e => { 
    const lastChild = e.target.lastElementChild;  
    if (lastChild && lastChild.matches('.menu.sub')) 
      return (e.target.classList.toggle('active'), undefined);  
    for (const mi of document.querySelectorAll('.menu > li')) 
      mi.classList.remove('active');  
  }); 
});
html, body { height: 100%; font-family: sans-serif; } 
.menu { list-style: none; font-size: 0; padding: 0; white-space: nowrap; } 
  .menu > li { position: relative; display: inline-block; padding: 0.5em; font-size: 1rem; box-shadow: 0 0 0 1px #777; user-select: none; cursor: pointer; } 
  .menu > li + li { margin-left: 1px; } 
.menu.sub { position: absolute; top: 100%; left: 0; display: none; width: 100%; } 
  .menu.sub > li { margin-top: 1px; } 
.menu > li.active { background: #def; } 
.menu > li.active > .menu.sub { display: inline-block; }
<ul class="menu"> 
  <li>flat</li> 
  <li>with submenu 
    <ul class="menu sub"> 
      <li>flat</li> 
      <li>flat</li> 
      <li>with submenu 
        <ul class="menu sub"> 
          <li>flat</li> 
        </ul> 
      </li> 
    </ul> 
  </li> 
  <li>flat</li> 
  <li>flat</li> 
</ul>

READ ALSO
Про html и javascript

Про html и javascript

У меня alert, prompt и прочие функции нормально работают в файле scriptjs, но вот вызов элементов и подобные штуки не работают

82
Nuxt env после build

Nuxt env после build

Подскажите, пожалуйста, как после генерации SPA Nuxt проекта (build) оставлять в нем конфиг (env или другой)?

121
Позиционирование и ширина блоков

Позиционирование и ширина блоков

Хочу сделать блоки как https://wp-kamaru/id_7686/miniatyury-dlya-elemetov-taksonomij

98