для Epic Skills
Динамики - никакой.
О пользователе можно узнать только то, что он открыл страницу. Да и то из логов бэкэнда.
Тут тебе и плеер, и облако ссылок, и вертикальные табы, и встроенный мессенджер, и куча магии 🎩
Но главное: в современном браузере работает javascript. И позволяет обрабатывать поведение пользователя.
Позволяет следить за любой мелочью, видеть всё, слушать всё.
Словно шпион.
Проблема: код реакции на пользователя и бизнес-логики сильно связан, при изменении одного приходится изменять и другой. Сложно реализовать связь один-ко-многим (я выпил кофе, надо внести изменения в кошелёк, в биохимическое состояние тела, в учёт лояльности кафе).
Решение: разнести источник и потребителей события. Источник не знает о подписчиках, но знает как известить их всех: он передаёт им событие
Калька с pattern. Устойчивая идея для решения проблемы.
Описывает проблему, дополнительные условия, идею решения. Не конкретная реализация, один и тот же паттерн можно реализовать множеством способов.
У посетителя сайта явно происходят какие-то события, а мы, как шпионы, можем их слушать, наблюдать.
О каких событиях мы можем знать?
Разберёмся, что есть в арсенале хорошего шпиона.
click
dblclick
mousemove
keydown
keyup
keypress
DOMContentLoaded
load
change
focus
submit
transitionend
Обработчик может быть назначен прямо в разметке, в атрибуте, который называется on<событие>.
<button onclick="alert('Клик!')">Жми!</button>
<button id="btn">Жми!</button>
<script>
document.getElementById('btn').onclick = function() {
alert('Клик!');
};
</script>
this
Внутри обработчика события this ссылается на тот элемент, на котором он сработал. Это можно использовать, чтобы получить, изменить элемент и его свойства.
<button onclick="alert(this.innerHTML)">Жми</button>
<button onclick="this.innerHTML='Нажми'">Жми</button>
Часто требуется отменять стандартное браузерное поведение.
<a href="vk.com" id="fun">Уходи!</button>
<script>
document.getElementById('fun').onclick = function(event) {
event.preventDefault();
};
</script>
Назначая обработчик через DOM-свойство, будьте осторожны. Нужно так elem.onclick = spy
, а не так elem.onclick = spy()
А вот если назначаешь через атрибут, то всё наоборот. Вот так правильно: <button onclick="spy()">
При использовании DOM-свойства важно понимать, что по клику должна выполниться функция.
Назначать так неправильно: elem.onclick = "spy()"
.
А вот так норм:
elem.onclick = function() {
spy();
}
<a href="vk.com" id="productivity">Важное решение!</button>
<script>
document.getElementById('productivity').onclick = kill;
document.getElementById('productivity').onclick = increase;
</script>
Какая функция выполнится при клике?
onclick
позволяет назначать обработчики, а нам нужно их добавлять.
Нужен другой способ добавления обработчиков. Нужен новый герой!
addEventListener
- добавляем обработчик
<a href="vk.com" id="productivity">Важное решение!</button>
<script>
var productivity = document.getElementById('productivity');
productivity.addEventListener('click', kill);
productivity.addEventListener('click', increase);
</script>
removeEventListener
- удаляем обработчик
Удаление требует ту же функцию
function kill(event) {
event.preventDefault();
}
var productivity = document.getElementById('productivity');
productivity.addEventListener('click', kill);
productivity.removeEventListener('click', kill);
Даже если код функций совпадает, обработчик не удалится.
var productivity = document.getElementById('productivity');
productivity.addEventListener('click', function(event) {
event.preventDefault();
});
productivity.removeEventListener('click', function(event) {
event.preventDefault();
});
События стилей (например, transitionend
) можно отследить только при помощи addEventListener
В IE8- работает альтернативный метод attachEvent
.
События могут возникать не только по очереди, но и «пачкой» по много сразу. Возможно и такое, что во время обработки одного события возникают другие, например пока выполнялся код для onclick – посетитель нажал кнопку на клавиатуре (событие keydown).
Когда происходит событие, оно попадает в очередь.
Иногда события добавляются в очередь сразу пачкой.
Клик: mousedown
при прожимании клавиши мыши, mouseup
при её отпускании. И click
сразу с mouseup
, ибо произошёл целый клик.
Обычно возникающие события «становятся в очередь».
Но в тех случаях, когда событие инициируется не посетителем, а кодом, то оно, как правило, обрабатывается синхронно, то есть прямо сейчас.
Есть хак, чтобы сделать события асинхронными: setTimeout(..., 0)
Каждый обработчик события передаёт объект события
var productivity = document.getElementById('productivity');
productivity.addEventListener('click', function(event) {
console.log(event.type); // click
console.log(event.target); // productivity
console.log(event.target); // productivity
});
При наступлении события обработчики сначала срабатывают на самом вложенном элементе, затем на его родителе, затем выше и так далее, вверх по цепочке вложенности.
Не все события всплывают
например, focus не всплывает.
target
vs currentTarget
На каком бы элементе мы ни поймали событие, всегда можно узнать, где конкретно оно произошло.
Самый глубокий элемент, который вызывает событие, называется «целевым» или «исходным» элементом и доступен как event.target
.
event.target
- это исходный элемент, на котором произошло событие, в процессе всплытия он неизменен.event.currentTarget
(=this
) – это текущий элемент, до которого дошло всплытие, на нём сейчас выполняется обработчик.На любом уровне всплытия можно указать, что событие полностью обработано, и остановить всплытие:
event.stopPropagation()
Кроме «всплытия» событий, предусмотрено ещё и «погружение». Оно гораздо менее востребовано, но иногда, очень редко, знание о нём может быть полезным. Стандарт выделяет три стадии прохода события:
Обычно про эту стадию не говорят, потому что, как правило, она не используется и проходит незаметно.
Чтобы поймать событие на стадии перехвата, нужно использовать третий аргумент addEventListener (фаза):
true
, то событие будет перехвачено по дороге вниз.false
, то событие будет поймано при всплытии.