Skip to main content

События

async.png

JS однопоточный. Очередь событий.

События в браузере

Для реакции на действия пользователя или внутреннее взаимодействие кода используют события — сигнал от браузера о том, что что-то произошло. События можно разделить на группы — в зависимости от устройства или элемента интерфейса, который дал им начало: События мыши

  • click — клик левой кнопкой мыши;
  • contextmenu — клик правой кнопкой мыши;
  • mouseover/mouseout — курсор попадает на элемент или уходит с него;
  • mousedown/mouseup — кнопку мыши нажали или отпустили;
  • mousemove — движение курсора над элементом.

click, submit, dblclick, keydown, keyup, keypress, mouseover, mouseout, reset, focus, focusin, focusout, change, blur


События клавиатуры

  • keydown — клавишу нажали;
  • keyup — клавишу отпустили.

key-codes

el.addEventListener('keydown', function(e) {
// js for keypress;
if (e.keyCode == 27) { ... }
});

События при нажатии пальцем

  • touchstart — элемента коснулись;
  • touchmove — по элементу провели пальцем;
  • touchend — касание закончилось и палец убрали;
  • touchcancel — палец переместился на интерфейс браузера или тач-событие нужно отменить.
el.addEventListener('click', (event) => {
// do smth
});

События на элементах управления

  • submit — нажали кнопку «Отправить» формы <form>;
  • reset — сбросили форму <form>;
  • focus — пользователь фокусируется на элементе, например, нажимает на <input>;
  • blur — пользователь выходит из фокуса элемента, например, кликает вне <input>.

Больше событий описано на MDN.

// onchange
el.onchange = () => { ... }

// onsubmit
el.onsubmit = () => { ... }

// onload
<body onload="alert('Страница загружена');">

Подписки. Добавление обработчика

Обработчик (от англ. handler) — это функция, которая отрабатывает, как только произошло событие. Именно он позволяет JavaScript-коду моментально реагировать на действия пользователя.


Через атрибут

Передать обработчик можно напрямую через атрибут onclick. У такого способа много ограничений и неудобств. Использовать его не стоит, кроме случаев, где это действительно нужно.

<button onclick="this.parentElement.innerHTML+='<span>click</span>'">
Нажми меня
</button>

Через свойства DOM-элемента

У элементов есть свойства on*, в которых можно присваивать обработчики. Но нужно быть готовым к тому, что явное присваивание заменяет все прошлые обработчики. Этот способ лучше не использовать без особой необходимости.

let count = 0;
const element = document.getElementsByTagName('BUTTON')[0];

element.onclick = function() {
element.innerHTML = `Кликнули ${++count} раз`;
}

addEventListener и removeEventListener

Самый верный способ навесить и удалить обработчик. Настоятельно рекомендуем использовать по умолчанию именно эти два метода:

// Добавление обработчика
element.addEventListener(event, handler);

// Удаление обработчика
// Нужно передать те же аргументы, что были у addEventListener
element.removeEventListener(event, handler);

////////////////////////////////////////////////

// Вот такой способ не сработает
// (в аргументах хоть внешне и одинаковые, но по сути разные функции)
element.addEventListener(event, () => '');
element.removeEventListener(event, () => '');

// Вот такой способ сработает (в аргументах одна и та же функция)
const handler = () => '';
element.addEventListener(event, handler);
element.removeEventListener(event, handler);

Подробнее про addEventListener на MDN.


event

Обработчики принимают на вход объект события event. Он сообщает свойства элемента на момент реагирования, что изменилось и что добавилось. Например, какая клавиша нажата. То есть можно определять не только абстрактные общие вещи вроде «нажали что-то».

element.addEventListener('click', function (event) {
console.log(`${event.type} на ${event.currentTarget}`);
console.log(`${event.clientX}:${event.clientY}`);
});

У event есть много разных свойств и методов. Подробный список найдёте на MDN. Свойства, которые показаны в примере:

  • event.type — тип события (в примере это 'click').
  • event.currentTarget — на каком элементе сработал обработчик. Не путайте с event.target, то есть исходным элементом, на котором произошло событие. Они могут быть разными из-за всплытия событий, о которых расскажем дальше.
  • event.clientX / event.clientY — свойства событий мыши, показывают координаты курсора относительно окна в момент клика.

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

Всплытие работает следующим образом. Сначала отрабатывают события на самом вложенном элементе, затем на его родителе, и так далее, вверх до window.

Например, возьмём форму. При нажатии на текст P будет показано три alert в следующем порядке:

  • alert('p') ,
  • alert('div'),
  • alert('form').
<form onclick="alert('form')">FORM
<div onclick="alert('div')">DIV
<p onclick="alert('p')">P</p>
</div>
</form>

Событие проходит следующие стадии:

  1. Перехват (capturing) — событие проходит сверху вниз.
  2. Цель (target) — событие достигло целевого элемента.
  3. Всплытие (bubbling) — событие идёт снизу вверх.

Самый глубокий элемент, который вызывает событие, называется целевым (target). Доступен из объекта события как event.target.

eventform.addEventListener('click', function(event) {
console.log('target = ', event.target.tagName); // target = FORM
console.log('this = ', this.tagName); // this = FORM
});

Работа с событием

  • event.preventDefault() — отменяет обработчик по умолчанию,

Код ниже вызовет переход на другую страницу, потому что таково поведение формы по умолчанию:

<form onsubmit="alert('submit!');">
Первый пример: нажмите Enter: <input type="text" value="Текст"><br>
Второй пример: нажмите на кнопку "Отправить": <input type="submit" value="Отправить">
</form>

Но если к обработчику в addEventListener добавить preventDefault, то перехода на другую страницу не будет.

  • event.stopPropagation — прекращает всплытие (например, при нажатии на кнопку не вызовет стандартное поведения <form>).
  • event.stopImmediatePropagation — прекращает всплытие и не выполняет оставшиеся обработчики события.

Перехват события

  • on* — обработчики не обрабатывают перехват;
  • element.addEventListener('event', callback, false) — обработка на стадии всплытия (поведение по умолчанию);
  • element.addEventListener('event', callback, true) — обработка на стадии перехвата.

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

Рассмотрим пример со списком. Есть список, в котором много дочерних элементов:

<ul>
<li>0</li>
<li>1</li>
<li>2</li>
</ul>

Как можно навесить обработчик на все элементы?

const logger = function(event) {
console.log(event.target.innerHTML);
}

const liElements = document.getElementsByTagName('li');

for (let i = 0; i < liElements.length; i++) {
const li = liElements[i];
li.addEventListener('click', logger);
}

Можно сделать намного проще, используя знания о делегировании, всплытии и перехвате:

const logger = function(event) {
if(event.target.tagName === 'LI') {
console.log(event.target.innerHTML);
}
}

const ul = document.getElementsByTagName('ul')[0];
ul.addEventListener('click', logger);

Преимущества данного подхода:

  • один обработчик вместо множества;
  • при добавлении новых элементов им не нужно добавлять обработчик.

onClick пример

Сработает только последний

btn.onclick = function () {
result.push('first event');
console.log(result);
}

btn.onclick = () => {
result.push('second event');
console.log(result);
};

btn.click();

Навешивание обработчика

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

const result = [];

btn.addEventListener('click', function(event) {
result.push('first event');
result.push('second event');
console.log(result);
});

Event loop

Бесконечный цикл, который постоянно крутиться интерпретатором и улавливает все события.

После того, как отлавливает события, то записывает их в СТЕК(очередь) ЗАДАЧ.

Задачи выполняются АСИНХРОННО, это означает, что если какая-либо задача выполняется, то Event loop не прекращается свою работу, а будет улавливать все события постоянно.


Список событий

EventOccurs WhenBelongs To
abortThe loading of a media is abortedUiEvent, Event
afterprintA page has started printingEvent
animationendA CSS animation has completedAnimationEvent
animationiterationA CSS animation is repeatedAnimationEvent
animationstartA CSS animation has startedAnimationEvent
beforeprintA page is about to be printedEvent
beforeunloadBefore a document is about to be unloadedUiEvent,Event
blurAn element loses focusFocusEvent
canplayThe browser can start playing a media (has buffered enough to begin)Event
canplaythroughThe browser can play through a media without stopping for bufferingEvent
changeThe content of a form element has changedEvent
clickAn element is clicked onMouseEvent
contextmenuПКМ: An element is right-clicked to open a context menuMouseEvent
copyThe content of an element is copiedClipboardEvent
cutThe content of an element is cutClipboardEvent
dblclickAn element is double-clickedMouseEvent
dragAn element is being draggedDragEvent
dragendDragging of an element has endedDragEvent
dragenterA dragged element enters the drop targetDragEvent
dragleaveA dragged element leaves the drop targetDragEvent
dragoverA dragged element is over the drop targetDragEvent
dragstartDragging of an element has startedDragEvent
dropA dragged element is dropped on the targetDragEvent
durationchangeThe duration of a media is changedEvent
endedA media has reach the end ("thanks for listening")Event
errorAn error has occurred while loading a file ProgressEvent,UiEvent, Event
focusAn element gets focusFocusEvent
focusinAn element is about to get focusFocusEvent
focusoutAn element is about to lose focusFocusEvent
fullscreenchangeAn element is displayed in fullscreen modeEvent
fullscreenerrorAn element can not be displayed in fullscreen modeEvent
hashchangeThere has been changes to the anchor part of a URLHashChangeEvent
inputAn element gets user inputInputEvent,Event
invalidAn element is invalidEvent
keydownA key is downKeyboardEvent
keypressA key is pressedKeyboardEvent
keyupA key is releasedKeyboardEvent
loadAn object has loadedUiEvent,Event
loadeddataMedia data is loadedEvent
loadedmetadataMeta data (like dimensions and duration) are loadedEvent
loadstartThe browser starts looking for the specified mediaProgressEvent
messageA message is received through the event sourceEvent
mousedownThe mouse button is pressed over an elementMouseEvent
mouseenterThe pointer is moved onto an elementMouseEvent
mouseleaveThe pointer is moved out of an elementMouseEvent
mousemoveThe pointer is moved over an elementMouseEvent
mouseoverThe pointer is moved onto an elementMouseEvent
mouseoutThe pointer is moved out of an elementMouseEvent
mouseupA user releases a mouse button over an elementMouseEvent
mousewheelDeprecated. Use thewheel event insteadWheelEvent
offlineThe browser starts working offlineEvent
onlineThe browser starts working onlineEvent
openA connection with the event source is openedEvent
pagehideUser navigates away from a webpagePageTransitionEvent
pageshowUser navigates to a webpagePageTransitionEvent
pasteSome content is pasted in an elementClipboardEvent
pauseA media is pausedEvent
playThe media has started or is no longer pausedEvent
playingThe media is playing after being paused or bufferedEvent
popstateThe window's history changesPopStateEvent
progressThe browser is downloading media dataEvent
ratechangeThe playing speed of a media is changedEvent
resizeThe document view is resizedUiEvent,Event
resetA form is resetEvent
scrollAn scrollbar is being scrolledUiEvent,Event
searchSomething is written in a search fieldEvent
seekedSkipping to a media position is finishedEvent
seekingSkipping to a media position is startedEvent
selectUser selects some textUiEvent,Event
showA <menu> element is shown as a context menuEvent
stalledThe browser is trying to get unavailable media dataEvent
storageA Web Storage area is updatedStorageEvent
submitA form is submittedEvent
suspendThe browser is intentionally not getting media dataEvent
timeupdateThe playing position has changed (the user moves to a different point in the media)Event
toggleThe user opens or closes the <details> elementEvent
touchcancelThe touch is interruptedTouchEvent
touchendA finger is removed from a touch screenTouchEvent
touchmoveA finger is dragged across the screenTouchEvent
touchstartA finger is placed on a touch screenTouchEvent
transitionendA CSS transition has completedTransitionEvent
unloadA page has unloadedUiEvent,Event
volumechangeThe volume of a media is changed (includes muting)Event
waitingA media is paused but is expected to resume (e.g. buffering)Event
wheelThe mouse wheel rolls up or down over an elementWheelEvent

Scroll, прокрутка до элемента

import { useEffect, useRef } from 'react';

const ref = useRef<HTMLDivElement>(null);

// Скроллинг до этого элемента, если он был последний просмотренный
useEffect(() => {
if (isLastEdited && ref.current) {
ref.current.scrollIntoView({ behavior: 'smooth' });
}
}, [isLastEdited]);

<div ref={ref}>
...
</div>