@anmkh

JS. Как при клонировании элемента сохранить события?

Есть меню, которое клонируется на мобилке в попап
// Бургер меню
const hamb = document.querySelector("#hamb");
const popup = document.querySelector("#popup");
const body = document.body;
const childMenu = document.querySelector('.menu-item-has-children')

// Клонируем меню, чтобы задать свои стили для мобильной версии
const menu = document.querySelector(".header__menu").cloneNode(1);
const contacts = document.querySelector(".header__contacts").cloneNode(1);
const address = document.querySelector(".header__address").cloneNode(1);
const actions = document.querySelector(".header__actions").cloneNode(1);

// При клике на иконку hamb вызываем ф-ию hambHandler
hamb.addEventListener("click", hambHandler);

// Выполняем действия при клике ..
function hambHandler(e) {
  e.preventDefault();
  e.stopPropagation();
  // Переключаем стили элементов при клике
  popup.classList.toggle("open");
  hamb.classList.toggle("active");
  body.classList.toggle("noscroll");
  renderPopup();
  
}

// Здесь мы рендерим элементы в наш попап
function renderPopup() {

  popup.appendChild(menu);
  popup.appendChild(contacts);
  popup.appendChild(address);
  popup.appendChild(actions);
}

document.addEventListener("click", function (e) {
  const target = e.target;
  const its_menu = target == popup || popup.contains(target);
  const its_btnMenu = target == hamb;
  const menu_is_active = popup.classList.contains("open");

  if (!its_menu && !its_btnMenu && menu_is_active) {
    popup.classList.remove("open");
    hamb.classList.remove("active");
    body.classList.remove("noscroll");
  }
});

// Закрытие попапа при клике на меню
function closeOnClick() {
  popup.classList.remove("open");
  hamb.classList.remove("active");
  body.classList.remove("noscroll");
}


Для дочерного меню есть такой скрипт со слушателями событий
// Меню по клику в шапке
document.addEventListener("DOMContentLoaded", () => {
  const headerSubmenuItem = document.querySelectorAll(".menu-item-has-children");
  const menuBody = document.querySelector(".sub-menu");
  const mainMenu = document.querySelector("#menu");

  headerSubmenuItem.forEach((item) => {
    item.addEventListener("click", handlerItem);

    // слушаем клик вне меню
    document.addEventListener("click", function (e) {
      const target = e.target;
      const its_menu = target == menuBody || menuBody.contains(target);
      const its_btnMenu = target == menuBody;
      const menu_is_active = item.classList.contains("--open");

      if (!its_menu && !its_btnMenu && menu_is_active) {
        item.classList.toggle("--open");
      }
    });
    // слушаем скролл
    document.addEventListener("scroll", function () {
      //убираем класс если произошел скролл
      item.classList.remove("--open");
    });
  });

  function handlerItem(e) {
      if (e.target.classList.contains('sub-menu-link') || e.target.closest('.sub-menu-link')) {
          // если нажата ссылка в подменю, то предотвращаем действие по умолчанию только для нее
          return;
        }

    const activeMenu = mainMenu.querySelector(".--open");

    if (activeMenu && !this.closest(".--open")) {

      activeMenu.classList.remove("--open");

    }
    e.preventDefault();
    e.stopPropagation();
    this.classList.toggle("--open");
    console.log(e)
  }
});


Но при клонировании не срабатывает скрипт для дочернего меню. Вероятно не клонируется слушатель, как это исправить?
  • Вопрос задан
  • 89 просмотров
Пригласить эксперта
Ответы на вопрос 1
delphinpro
@delphinpro Куратор тега JavaScript
frontend developer
Второй скрипт для дочернего меню написан криво.
headerSubmenuItem.forEach((item) => {
    document.addEventListener("click", function (e) {
    });
});


Слушатель вешается на весь документ, очевидно, используется делегация. Но при этом слушатель вызывается энное количество раз, по количеству сабитемов.

Я бы переписал, вынеся document.addEventListener на верхний уровень, и поиск необходимых элементов выполнял бы уже внутри этого обработчика. Тогда будет неважно, когда меню появится на странице, клонировано оно, или нет.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы