базовый курс

ГРУППА КУРСА

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

Всплытие событий

Когда какое-то событие возникает на элементе, то оно срабатывает не только на этом элементе, но и на всех внешних элемнтах. То есть на элементах, внутри которых находится этот элемент. Самый вложенный элемент, на котором сработало событие, называется целевой элемент. На нём событие срабатывает в первую очередь. Затем оно срабатывает на внешнем элементе, затем на ещё более внешнем, и так до самого внешнего элемента. Если на каких-то из этих элементов есть обработчики, то они срабатывают именно в таком порядке. Обработчики выполняются по очереди. Сначала выполняется один и только потом начинает работать следующий.

Создадим два блока, внешний и вложенный. Поставим на оба блока обработчик события click:

Стиль:

7
8
9
10
div
  {
  border: 1px solid Red;
  }

HTML код:

14
15
16
<div id="big" style="width: 150px; height: 80px">
  <div id="smal" style="width: 50px; height: 70px"></div>
</div>

JavaScript:

18
19
20
21
22
23
24
25
let big = document.getElementById('big');
let smal = document.getElementById('smal');
big.onclick = function() {
  alert('Клик на большом блоке');
  };
smal.onclick = function() {
  alert('Клик на маленьком блоке');
  };

Запустите страницу и кликните на маленьком блоке. Событие сработает сначала на маленьком, а затем на большом блоке.

Есть события, на которых всплытие не работает. Например mouseenter и mouseleave. Если нужно использовать всплытие, то можно использовать события mouseover и mouseout. Кроме того, всплытие не работает для события прокрутки.

У объектов событий есть свойство target. Оно содержит целевой элемент, то есть самый вложенный элемент, на котором сработало событие. При всплытии события в обработчиках всех элементов это свойство остаётся неизменным. Также есть свойство currentTarget. Оно содержит элемент, на котором выполняется обработчик.

Делегирование

Иногда есть необходимость нескольким элементам назначить одинаковые обработчики. Самый очевидный вариант - создать функцию и указать её в каждом обработчике. Но тогда нужно найти все элементы и создать отдельный обработчик для каждого элемента. А их может быть очень много. В дальнейшем может быть добавлено ещё некоторое количество элементов. Всплытие позволяет использовать приём, который называется делегирование. При делегировании ставится только один обработчик на внешний элемент, внутри которого находятся все нужные элементы. С помощью свойства target можно определить конкретный элемент, на котором сработало событие. И с этим элементом производятся какие-то действия.

Создадим блок, в котором будут перечислены города. При нажатии на название города, оно должно становиться первым в списке:

Стиль:

11
12
13
14
15
16
17
p
  {
  cursor: default;
  width: 200px;
  margin: 10px;
  background-color: #CCC;
  }

HTML код:

24
25
26
27
28
29
30
<div id="div">
  <p>Красноярск</p>
  <p>Новосибирск</p>
  <p>Санкт-Петербург</p>
  <p>Хабаровск</p>
  <p>Екатеринбург</p>
</div>

JavaScript:

40
41
42
43
44
45
46
47
let div = document.getElementById('div');

div.onclick = function(event)
{
  let target = event.target;
  if (target.tagName == 'P')
  div.prepend(target);
};

Нужно обязательно учитывать то, что событие может произойти не на том элементе, с которым нужно работать, а на каком-то другом. В нашем примере клик может произойти не на названии города, а просто внутри внешнего блока. Тогда свойство target будет содержать этот блок. В этом случае обработчик не должен производить никаких действий. Поэтому в строке 44 есть условие - если target является тэгом <p>, только тогда с ним производятся определённые действия.

У делегирования есть одно ограничение: элемент, с которым нужно работать, должен быть самым вложенным. Если в нашем примере внутри тэга <p> будет какой-нибудь элемент и клик сработает на этом элементе, то свойство target будет содержать этот элемент. В этом случае обработчик несколько усложняется. Нужно искать тэг <p> среди внешних элементов, внутри которых содержится target. Если он будет найден, то к нему применяются какие-то действия.