Метод addEventListener
- это самый функциональный способ позволяющий добавить обработчик события к указанному элементу и запустить выполнение программы при совершении заданного действия. Получить информацию о сигналах браузера можно из Document
(DOM), Element
, Window
и других объектов поддерживающих события.
addEventListener()
является одних из трёх способом прослушивать события, наряду с добавление атрибута к тегам в HTML и обращения к свойствам объекта напрямую.
<!-- добавление атрибута -->
<button onclick="alert('Терпение и труд всё перетрут')">Хочу стать программистом!</button>
<script>
const myFirstEvent = document.querySelector('button');
// обращаемся к свойству напрямую
myFirstEvent.onclick = function() {
alert('Да будет так!');
}
// используем метод addEventListener
myFirstEvent.addEventListener('click', function() {
alert('Дорогу осилит идущий');
})
</script>
addEventListener()
имеет важное преимущество перед остальными способами, метод позволяет навесить несколько обработчиков на одно событие. Это происходит из-за того, что у объекта только одно свойство, например с именем onclick
(клик) или mousemove
(движение мыши) и если обратиться к одному из них напрямую несколько раз, второй обработчик перезапишет первый.
В примере выше, как раз можно наблюдать описанный эффект - модальное окно с Да будет так! появится, а вот Терпение и труд всё перетрут нет.
Также отследить некоторые события можно только с помощью addEventListener()
, например навесить обработчик на DOMContentLoaded
по другому не получиться.
element.addEventListener(eventType, handler, options);
element
- объект, действие по которому отслеживаем.
eventType
- тип события, которое мы хотим отследить: клик, прокрутка мыши, нажатие клавиши и т.д. Написание чувствительно к регистру: click
правильно, Click или CLICK неправильно.
handler
- имя функции или сама функция, которая будет выполнена после наступления события.
options
- необязательный объект со свойствами, внутри которого доступны следующие параметры:
capture
: значение записывается в формате true
или false
и задает этап, на котором будет обработано событие. По умолчанию false
- на этапе всплытия, true
- на этапе погружения (перехват). Если вместо options
задать булево значение - это будет равносильно {capture: false/true}
once
: значение типа boolean
, по умолчанию false
, если true
тогда обработчик будет удален после выполнения.passive
: по умолчанию false
, если true
обработчик никогда не вызовет preventDefault()
, взамен этого будет сгенерировано предупреждение в console.
<button>В скором времени я стану JavaScript middle</button>
<script>
const clickButton = document.querySelector('button');
clickButton.addEventListener('click', showMessage, {
capture: false,
once: true,
passive: false,
})
function showMessage() {
alert('У тебя все получиться, я в тебя верю!');
}
</script>
При клике на кнопку мы получим модальное окно с сообщением, если кликнуть второй раз ничего не произойдет, так как свойство once
равно true
- после события обработчик удаляется.
Удалить обработчик события можно также с помощью метода removeEventListener()
. В этом случае появляется возможность сделать это когда нам удобно. Для того, чтобы все сработало, первые два параметра у обоих методов должны быть идентичными. Важно также передать в removeEventListener()
именно название функции, с анонимными функциями ничего не получиться, даже если записать код точь в точь.
<button>Удалить обработчик события</button>
<script>
const clickButton = document.querySelector('button');
clickButton.addEventListener('click', showMessage);
function showMessage() {
if (clickButton.innerText === 'Удалить обработчик события') {
alert('Обработчик удален');
clickButton.removeEventListener('click', showMessage);
} else {
alert('Обработчик не удален');
}
}
</script>
В этом случае, если поменять текст на кнопке обработчик удален не будет.
Для более детального представления о том какие действия происходят на странице используют объект события, который создается браузером после совершения действия. Такой объект записывается в качестве первого аргумента функции обработчика, для названия принято использовать event
. Это позволяет гибко настраивать отслеживание получая информацию о том какая клавиша была нажата, координаты указателя мыши и другое.
<button class="btn">JavaScript</button>
<script>
const btnJS = document.querySelector('.btn');
btnJS.addEventListener('click', showElemObjEvent);
function showElemObjEvent(event) {
console.log(event.type); // тип события
console.log(event.target); // элемент на котором произошло событие
console.log(event.clientX); // координаты курсора по оси X
console.log(event.clientY); // координаты курсора по оси Y
console.log(event); // получим весь объект с информацией о событии
}
</script>
Рассмотрим события, которые отслеживаются чаще других:
click
- клик левой кнопкой мыши по элементу, на сенсорных устройствах это касание;
contextmenu
- клик на элемент правой кнопкой мыши - вызов контекстного меню;
mouseover
/ mouseout
- наведение на элемент курсора мыши / курсор покидает элемент;
mousemove
- движение мыши;
keydown
/ keyup
- клавиша нажата / клавиша отпущена;
DOMContentLoaded
- весь HTML загружен, а DOM-дерево построено.
Для того, чтобы посмотреть все возможные события для DOM-элемента, нажмите правой кнопкой на страницу, далее Просмотреть код, выберите элемент на странице, а далее кликните на Свойства (Properties). В фильтре наберите on, все что начинает на on являются событиями.
<button class="myChoice">JavaScript</button>
<button class="myChoice">Python</button>
<script>
const choice = document.querySelectorAll('.myChoice');
choice.forEach(choiceItem => {
choiceItem.addEventListener('click', () => answer(choiceItem.innerHTML));
})
function answer(text) {
if (text === 'JavaScript') {
alert('Отличный выбор!');
} else {
alert('Возможно вы ошиблись?');
}
}
</script>
В данном примере мы получили все элементы с классом myChoice
в объект через querySelectorAll()
, а потом с помощью forEach()
перебором назначили обработчик события на все кнопки.
Вторым и более удачным способом отслеживать события на множестве элементов это делегирование.
<style>
td {
border: 1px solid;
width: 90px;
height: 90px;
text-align: center;
border-color: black;
}
.hideText {
color: white;
}
</style>
<table>
<td class="hideText">JavaScript</td>
<td class="hideText">React</td>
<td class="hideText">HTML</td>
</table>
<script>
const getTable = document.querySelector('table');
getTable.addEventListener('click', function(event) {
if (event.target.closest('.hideText')) {
event.target.classList.remove('hideText');
}
})
</script>
В этом примере мы назначаем обработчик для родителя в котором содержатся интересующие нас элементы. Далее отслеживаем с помощью event.target.closest('.hideText')
было ли взаимодействие с тегом с классом .hideText
и если это так удаляем оттуда класс, который делает текст белым.
Всплытие - это когда обработчик сначала срабатывает на элементе с которым произошло взаимодействие, затем событие обрабатывается на его родителе и далее выше по цепочке.
<body> в четвертую очередь
<span></span> не сработает
<span> в третью очередь
<span> во вторую очередь
<span></span> кликаем сюда - обработчик сработает на этом элементе в первую очередь
</span>
</span>
</body>
Погружение - при взаимодействии с объектом, который находится ниже чем элемент со свойством capture: true
, сначала событие будет обработано на последнем, далее обработчик сработает на всех потомках и только потом на всех родителях.
<body> в пятую очередь
<span></span> не сработает
<span> в четвертую очередь
<span> - элемент со свойством capture: true - в первую очередь
<span> - в третью очередь
<span></span> кликаем сюда - обработчик сработает на этом элементе во вторую очередь
</span>
</span>
</span>
</body>
Для того, чтобы понять тему потренируйтесь на примере, наблюдая последовательность выполнения действий при клике на различные элементы. Результат отслеживайте в console.
Пример с квадратами
<style>
.square1 {
width: 600px;
height: 600px;
background: red;
display: flex;
justify-content: center;
align-items: center;
}
.square2 {
width: 450px;
height: 450px;
background: blue;
display: flex;
justify-content: center;
align-items: center;
}
.square3 {
width: 350px;
height: 350px;
background: yellow;
display: flex;
justify-content: center;
align-items: center;
}
.square4 {
width: 250px;
height: 250px;
background: white;
display: flex;
justify-content: center;
align-items: center;
}
</style>
<div class="square1">
<div class="square2">
<div class="square3">
<div class="square4"></div>
</div>
</div>
</div>
<script>
const squareFirst = document.querySelector('.square1');
const squareSecond = document.querySelector('.square2');
const squareThird = document.querySelector('.square3');
const squareFourth = document.querySelector('.square4');
squareFirst.addEventListener('click', () => clickSquare('Квадрат №1'));
squareSecond.addEventListener('click', () => clickSquare('Квадрат №2'));
squareThird.addEventListener('click', () => clickSquare('Квадрат №3'), { "capture": true });
squareFourth.addEventListener('click', () => clickSquare('Квадрат №4'));
function clickSquare(text) {
console.log(text);
}
</script>
Для того, чтобы получить доступ к элементу на котором висит обработчик, в функции можно использовать this
.
<button class="btn">После того, как выучу JS примусь за React</button>
<script>
const getButton = document.querySelector('.btn');
getButton.addEventListener('click', printBtnText);
function printBtnText() {
alert(this.innerHTML);
}
</script>
Обработчик события это важный элемент в JavaScript, именно с помощью него можно отслеживать действия пользователя на странице. В свою очередь метод addEventListener()
является основным способом для назначения таких обработчиков объектам.
Удалить обработчик события после использования можно двумя способами: с помощью свойства once
со значением true
или метода removeEventListener()
.
Для того, чтобы получить более подробную информацию о событии используют объект события, который передается первым аргументом в функцию. Отсюда можно получить координаты клика, какая кнопка была нажата и многое другое.
Для того, чтобы назначить обработчик множеству элементов используют принцип делегирования - событие фиксируется не только на элементе которому был назначен обработчик, но и на всех вложенных. Второй способ - это навешивание обработчиков через цикл forEach()
.