Помогите разобраться с addEventListener

https://repl.it/repls/RapidSlowApplications

При нажатии на текст цвет не меняется. То есть дело в том, что я нажимаю на span, вложенный в li. При нажатии на весь элемент, который подсвечивается при наведении, всё отрабатывает, как ожидается.
Можно ли обойти эту проблему, не меняя разметку?

https://learn.javascript.ru/event-delegation
У статті про делегування в принципі є декілька пропозицій. (та пояснення чому така проблема існує)

Варіант, якщо таргет не LI елемент, то пошукати його серед батьківських елементів. Але десь треба зупинитись обов’язково щоб не піти до Баді -)

Якщо без делегування, можна навісити лістенер на кожен елемент LI :)

“не кроссбраузерний” closest()
https://repl.it/repls/RaggedRectangularNamebinding

Дело в том что в evt.target хранятся разные значения в зависимости от клика по span или по li. Соответственно нужно моделировать решение учитывая этот нюанс.

evt.target.firstChild - моделировать приложение используя последовательность элементов - хрупкое занятие. Лучше привязываться к названиям классов. А еще лучше отдельно хранить данные и отдельно рендерить их представление (но это требует большей подготовки).

Когда-то писал функцию которая “бегает” вверх по дереву от узла. https://github.com/podgorniy/javascript-toolbox/blob/master/top_walker.js Это как раз то что тебе нужно: при клике найти элемент li по которому был клик, и уже от li отталкиваться.

function top_walker(node, test_func, last_parent) {
  while (node && node !== last_parent) {
    if (test_func(node)) {
      return node;
    }
    node = node.parentNode;
  }
}

const currentColorEl = document.querySelector('.color-panel__bg--current');
const prevColorEl = document.querySelector('.color-panel__bg--prev');
let currentColor = getComputedStyle(currentColorEl).backgroundColor;
let prevColor = getComputedStyle(prevColorEl).backgroundColor;
const customColorInput = document.querySelector('#custom-color');
const customColorEl = document.querySelector('.color-panel__bg--custom');
const buttonsPanel = document.querySelector('.buttons-panel');
const colorPanel = document.querySelector('.color-panel');
colorPanel.addEventListener('click', function(evt) {
  console.log(evt.target, this);
  customColorEl.style.backgroundColor = customColorInput.value;
  customColorInput.addEventListener('change', function(evt) {
    customColorEl.style.backgroundColor = customColorInput.value;
    currentColorEl.style.backgroundColor = customColorInput.value;
    currentColor = currentColorEl.style.backgroundColor;
  })

  var panelListItem = top_walker(event.target, function(node) {
    return node.matches('.color-panel__item')
  }, colorPanel)

  // Клик по чему-то внутри элемента li, но не по его первому ребенку
  if (!event.target.matches('.color-panel__item:first-child') && panelListItem) {
    let changedColor = currentColor;
    currentColorEl.style.backgroundColor = getComputedStyle(panelListItem.firstChild).backgroundColor;
    currentColor = currentColorEl.style.backgroundColor;
    prevColor = getComputedStyle(panelListItem.firstChild).backgroundColor;
    prevColorEl.style.backgroundColor = changedColor;
  }
});

https://repl.it/repls/RoundPleasantWebsites

UPD @Maxim прав, можно использовать делегирование чтобы решить задачу. И в моем и в его варианте ты будешь отталкиваться от li элемента.

Оба варианта не позволяет выбрать форум. Большое вам спасибо, не догадалась до closest сама.

Рано обрадовалась. При выборе цвета из custom color меняются сразу и current, и prev. Почему так происходит, не понимаю.

Обработчик клика по .color-panel__bg--custom элементу вызывается дважды (раз когда кликаешь по li элементу, второй раз когда срабатывает механика аттрибута for="custom-color". Второй раз происходит “клик” по элементу с айдишником “custom-color” и вся логика обработчика выполняется заново.


В самом подходе могли закраться проблемы. Возможно понадобится пересматривать подход, а не просто пытаться заставить работать то что есть. Не бойся изменить подход после того как узнала достаточно про задачу, возможности/ограничения браузера.

И если хочешь улучшить код, то вынеси навешивание обработчиков из вызова обработчиков. Это ненадежное решение с проблемами производительности и понимания.

Я б порадив рознести загальну логіку на окремі функції, наприклад setCurrentColor(color) , setPrevColor() , getNewColor(element)

Таким чином краще дебажити функціонал та розуміти в якому місці помилка.
Тут ще проблема є що на кожен клік додається лістенер на customColorInput , та кількість лістенерів постійно збільшується.

в мене взагалі change на input type=color не відпрацьовують :)

1 лайк

Работает, но не совсем верно…)
Наверное проблема действительно в том, что боюсь что-то глобально менять, дабы не развалить то. что есть.
Спасибо за советы!