Главная » Свойство classList. Делегирование событий.

Свойство classList. Делегирование событий.


19.04.2021, 11:22
Свойство classList и его методы

Значением свойства classList является итерируемый массивоподобный объект.

В этом свойстве определены следующие методы:

add() - добавление класса для элемента

remove() - удаление класса у элемента

contains() - проверка определённого класса на конкретном элементе

toggle() - переключатель класса для элемента (если он есть - удаляет класс, если нет - добавляет класс элементу)

Чтобы обратиться к этому свойству, необходимо через точку прописать его:

Код

element.classList.add('home'); // => добавили элементу класс home

Код

element.classList.add('home', 'active'); // => добавили элементу классы home и active

Код

element.classList.remove('home', 'active'); // => удалили у элемента классы home и active

узнать количество имеющихся классов у элемента (и, например, вывести его в консоль):

Код

<button class = "btn blue">Кнопка</button>

Код

const btn = document.querySelector('button');
console.log(btn.classList.length); // => 2

Свойство classList позволяет обращаться с атрибутом class как со списком. С помощью метода item() мы можем получить класс элемента под определённым индексом:

Код

console.log(btn.classList.item(0)); // => btn

Проверяем наличие определённого класса у элемента:

Код

<button class = "btn blue">Кнопка</button>

Код

const btn = document.querySelector('button');

if (btn.classList.contains('btn')) {
  console.log('Такой класс есть');
} else {
  console.log('Такого класса нет');
} // => Такой класс есть

Добавляем и удаляем класс для элемента, исходя из условия:

Код

<button class = "btn blue">Кнопка</button>  
<p class="hidden">Какой-то текст на странице</p>  

Код

const btn = document.querySelector('button'); /* получаем кнопку */
const p = document.querySelector('p'); /* получаем параграф */

btn.addEventListener('click', () => {
  if (p.classList.contains('hidden')) {
  p.classList.remove('hidden'); /* если класс уже есть, удаляем его */
  } else {
  p.classList.add('hidden'); /* если класса нет, добавляем его */
  }
});

Тоже самое, но используя метод toggle():

Код

btn.addEventListener('click', () => {
  p.classList.toggle('hidden'); /* добавляем или удаляем класс, в зависимости от его наличия у элемента */
});

Устаревшее свойство className - содержит классы в виде одной строки, что неудобно.

Код

<button class = "btn blue">Кнопка</button>

Код

const btn = document.querySelector('button');

console.log(btn.className); // => btn blue

Делегирование событий

Пример: есть блок-обёртка с кнопками внутри

Код

  <div class="wrapper">
  <button class="btn btn-outline-primary">Кнопка</button>
  <button class="btn btn-outline-primary">Кнопка</button>
  <button class="btn btn-outline-primary">Кнопка</button>
  <button class="btn btn-outline-primary">Кнопка</button>
  <button class="btn btn-outline-primary">Кнопка</button>
  </div>

Как назначить одно и тоже событие для каждой кнопки? Например, чтобы при клике на любую из них в консоль выводилось сообщение "Кнопка нажата"?

Можно, конечно, перебрать выборку кнопок методом forEach(), как мы это уже делали ранее

Код

const btns = document.querySelectorAll('button');

btns.forEach(btn => {
  btn.addEventListener('click', () => {
  console.log('Кнопка нажата');
  });
});

Но если мы добавим новую кнопку динамически, то для нее обработчик события не сработает, так как она не попадёт в перебор:

Код

const wrapper = document.querySelector('.wrapper'); /* получили родительский элемент */
const btns = document.querySelectorAll('button'); /* получили все кнопки родителя */

btns.forEach(btn => {
  btn.addEventListener('click', () => {
  console.log('Кнопка нажата');
  });
}); /* назначили всем кнопкам один обработчик события */

const newBtn = document.createElement('button'); /* создали новую кнопку */
wrapper.append(newBtn); /* добавили динамически в блок родителя */

При клике на добавленную кнопку ничего не происходит.

При помощи же делегирования события мы можем решить эту задачу.

Смысл делегирования в данном случае в том, что обработчик события клика мы назначаем на родительский элемент (div с классом wrapper), а внутри создаём условие для потомков, которое будет отрабатывать в случае, если они подходят под определённые параметры.

Код

const wrapper = document.querySelector('.wrapper'); /* получили родительский элемент */
const btns = document.querySelectorAll('button'); /* получили все кнопки родителя */

wrapper.addEventListener('click', (event) => {
  if (event.target && event.target.tagName == 'BUTTON' /* проверка что элемент поддерживает событие клика и что клик был именно по кнопке */) {  
  console.log('Кнопка нажата');
  }
});

const newBtn = document.createElement('button'); /* создали новую кнопку */
wrapper.append(newBtn); /* добавили в блок родителя */

Теперь, даже если кнопка добавляется динамически, при клике на неё в консоли также будет выведено сообщение "Кнопка нажата"

При этом, если кликать не по кнопке, а по фону родительского блока, то ничего происходить не будет, поскольку событие клика делегировано с блока на его потомков (на кнопки).

Можно делегировать событие на элемент с конкретным классом, например, для одной из кнопок добавим класс active

Код

  <div class="wrapper">
  <button class="active">Кнопка</button>
  <button>Кнопка</button>
  <button>Кнопка</button>
  <button>Кнопка</button>
  <button>Кнопка</button>
  </div>

Код

const wrapper = document.querySelector('.wrapper'); /* получили родительский элемент */
const btns = document.querySelectorAll('button'); /* получили все кнопки родителя */

wrapper.addEventListener('click', (event) => {
  if (event.target && event.target.classList.contains('active')) {
  console.log('Кнопка нажата');
  }
});

И теперь, только при клике на кнопку с этим классом, в консоли будет выводиться сообщение "Кнопка нажата"

Вариант делегирования с применением метода matches(), который проводит проверку на совпадение с указанным CSS-селектором :

Код

wrapper.addEventListener('click', (event) => {
  if (event.target && event.target.matches('button.active') {
  console.log('Кнопка нажата');
  }
});

КОММЕНТАРИИ (0)