Как закрыть меню при нажатии на один из элементов?

Не понимаю почему функция closeMenu не отрабатывает

const burger = document.querySelector('.burger')
const mobileMenu = document.querySelector('.mobile-menu')
const mainMenu = document.querySelector('.main-menu').cloneNode(true)
const headerCeos = document.querySelector('.header__ceos').cloneNode(true)
const headerCeosItems = document.querySelectorAll('.header__ceos-item')
const body = document.body

burger.addEventListener('click', burgerHandler)

function burgerHandler(e) {
  e.preventDefault()
  mobileMenu.classList.toggle('open')
  burger.classList.toggle('active')
  body.classList.toggle('noscroll')
  renderMobileMenu()
}

function renderMobileMenu() {
  mobileMenu.append(mainMenu, headerCeos)
}

headerCeosItems.forEach(el => el.addEventListener('click', closeMenu))

function closeMenu() {
  mobileMenu.classList.remove('open')
}
.main-menu__list {
  list-style-type: none;
  margin: 0;
  padding: 0;
  text-align: center;
}
.main-menu__item {
  display: inline-block;
  margin: 0 10px;
  position: relative;
}
.burger {
  background: transparent;
  border: none;
  padding: 0;
  cursor: pointer;
  position: relative;
  vertical-align: middle;
  width: 26px;
  height: 16px;
  margin-left: 10px;
}

.burger__icon,
.burger__icon::after,
.burger__icon::before {
  background-color: blue;
  position: absolute;
  width: 26px;
  height: 2px;
  transition: all .2s ease-out;
  display: block;
  right: 0;
}

.burger__icon::after, 
.burger__icon::before {
  content: '';
}

.burger__icon::before {
  top: -7px;
}

.burger__icon::after {
  bottom: -7px;
}

.burger.active .burger__icon {
  background-color: transparent;
}

.burger.active .burger__icon::before {
  top: 0;
  transform: rotate(45deg);
}

.burger.active .burger__icon::after {
  bottom: 0;
  transform: rotate(-45deg);
}

.header__ceos {
  text-align: center;
  margin-top: 30px;
}

.header__ceos-item {
  margin: 0 10px;
}

.mobile-menu {
  position: fixed;
  top: 30px;
  right: -100%;
  width: 100%;
  background-color: grey;
  z-index: 10;
  padding: 30px 0;
  transition: all .3s ease-out;
}

.mobile-menu.open {
  right: 0;
}

.mobile-menu .header__ceos-item {
  color: #fff;
}
<button class="burger">
  <i class="burger__icon"></i>
</button>

<nav class="main-menu">
  <ul class="main-menu__list">
    <li class="main-menu__item">
      <a class="main-menu__link" href="#">Пункт 1</a>
    </li>
    <li class="main-menu__item">
      <a class="main-menu__link" href="#">Пункт 2</a>
    </li>
    <li class="main-menu__item">
      <a class="main-menu__link" href="#">Пункт 3</a>
    </li>
  </ul>
</nav>

<div class="header__ceos">
  <a class="header__ceos-item" href="#">
    <span class="header__ceos-name">Имя 1</span>
  </a>
  <a class="header__ceos-item" href="#">
    <span class="header__ceos-name">Имя 2</span>
  </a>
  <a class="header__ceos-item" href="#">
    <span class="header__ceos-name">Имя 3</span>
  </a>
</div>

<div class="mobile-menu"></div>


Ответы (1 шт):

Автор решения: Gene Erbin

Когда клонируется Node здесь const headerCeos = document.querySelector('.header__ceos').cloneNode(true), существует только переменная, содержащая элемент, но сам этот элемент на странице не появляется, а появляется только при выполнении mobileMenu.append(mainMenu, headerCeos).

Вот только mobileMenu.append(mainMenu, headerCeos) выполняется при клике на бургер, а выбор всех элементов const headerCeosItems = document.querySelectorAll('.header__ceos-item') осуществляется сразу при выполнении скрипта и он вернёт только три элемента из main-menu, так как в mobile-menu на момент выполнения не существует элементов.

Ну и тогда запись headerCeosItems.forEach(el => el.addEventListener('click', closeMenu)) назначит обработчики события только на три элемента .header__ceos-item, которые принадлежат элементу main-menu, а элементы .header__ceos-item, принадлежащие mobile-menu, появятся на странице только после клика на бургер и не будут иметь обработчиков события click.

Немного сумбурно получилось, но, надеюсь, смысл понятен.

Ниже рабочий вариант с внесением поиска элементов .header__ceos-item и назначения им обработчиков события в функцию рендера мобильного меню после того, как в mobile-menu добавились элементы.

Либо в вашем исходном коде можно просто mobileMenu.append(mainMenu, headerCeos) вставить сразу после const headerCeos = document.querySelector('.header__ceos').cloneNode(true), а объявление функции renderMobileMenu() и её вызов в burgerHadler удалить.

const burger = document.querySelector('.burger')
const mobileMenu = document.querySelector('.mobile-menu')
const mainMenu = document.querySelector('.main-menu').cloneNode(true)
const headerCeos = document.querySelector('.header__ceos').cloneNode(true)
const body = document.body

burger.addEventListener('click', burgerHandler)

function burgerHandler(e) {
  e.preventDefault()
  mobileMenu.classList.toggle('open')
  burger.classList.toggle('active')
  body.classList.toggle('noscroll')
  renderMobileMenu()
}

function renderMobileMenu() {
  mobileMenu.append(mainMenu, headerCeos)
  const headerCeosItems = mobileMenu.querySelectorAll('.header__ceos-item')
  headerCeosItems.forEach(el => el.addEventListener('click', closeMenu))
}


function closeMenu() {
  mobileMenu.classList.remove('open')
}
.main-menu__list {
  list-style-type: none;
  margin: 0;
  padding: 0;
  text-align: center;
}
.main-menu__item {
  display: inline-block;
  margin: 0 10px;
  position: relative;
}
.burger {
  background: transparent;
  border: none;
  padding: 0;
  cursor: pointer;
  position: relative;
  vertical-align: middle;
  width: 26px;
  height: 16px;
  margin-left: 10px;
}

.burger__icon,
.burger__icon::after,
.burger__icon::before {
  background-color: blue;
  position: absolute;
  width: 26px;
  height: 2px;
  transition: all .2s ease-out;
  display: block;
  right: 0;
}

.burger__icon::after, 
.burger__icon::before {
  content: '';
}

.burger__icon::before {
  top: -7px;
}

.burger__icon::after {
  bottom: -7px;
}

.burger.active .burger__icon {
  background-color: transparent;
}

.burger.active .burger__icon::before {
  top: 0;
  transform: rotate(45deg);
}

.burger.active .burger__icon::after {
  bottom: 0;
  transform: rotate(-45deg);
}

.header__ceos {
  text-align: center;
  margin-top: 30px;
}

.header__ceos-item {
  margin: 0 10px;
}

.mobile-menu {
  position: fixed;
  top: 30px;
  right: -100%;
  width: 100%;
  background-color: grey;
  z-index: 10;
  padding: 30px 0;
  transition: all .3s ease-out;
}

.mobile-menu.open {
  right: 0;
}

.mobile-menu .header__ceos-item {
  color: #fff;
}
<button class="burger">
  <i class="burger__icon"></i>
</button>

<nav class="main-menu">
  <ul class="main-menu__list">
    <li class="main-menu__item">
      <a class="main-menu__link" href="#">Пункт 1</a>
    </li>
    <li class="main-menu__item">
      <a class="main-menu__link" href="#">Пункт 2</a>
    </li>
    <li class="main-menu__item">
      <a class="main-menu__link" href="#">Пункт 3</a>
    </li>
  </ul>
</nav>

<div class="header__ceos">
  <a class="header__ceos-item" href="#">
    <span class="header__ceos-name">Имя 1</span>
  </a>
  <a class="header__ceos-item" href="#">
    <span class="header__ceos-name">Имя 2</span>
  </a>
  <a class="header__ceos-item" href="#">
    <span class="header__ceos-name">Имя 3</span>
  </a>
</div>

<div class="mobile-menu"></div>

→ Ссылка