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

#1

https://repl.it/repls/RapidSlowApplications

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

#2

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

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

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

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

#3

Дело в том что в 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 элемента.

#4

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

#5

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

#6

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


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

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

[TIL] label с аттрибутом "for" генерирует событие "click" по input
#7

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

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

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

1 Like
#8

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