Сегодня, стало более ли менее стандартом использование синтетических событий в современных js фреймворках, нежели обычный addEventListener
. Но, как же работают эти события? В данной статье, я постараюсь на примере клика в Cample.js версии 3.2.0-beta.1 рассказать об этом.
Прежде всего, когда говорится о работе с событиями, очевидно, что речь заходит о конструкции addEventListener
, которая выглядит следующим образом:
element.addEventListener("событие", "функция", useCapture или options);
Но, так ли это универсально? Как оказалось, это не совсем универсально.
Когда речь заходит о фреймворках, важна кроссбраузерность, которая позволяет охватить большие пользовательские устройства.
Поэтому, нужно было придумать альтернативу, которая заменит такой подход на более универсальный, чтобы все события имели одинаковые свойства.
Самая банальная идея событий на сайте — что‑то выдаёт действие будь то мышка или клавиатура, а javascript вызывает функцию, которая на это событие срабатывает.
У события есть три фазы:
Фаза захвата. Погружение в DOM.
Фаза цели. Событие срабатывает на элемент, на который собственно кликается.
Фаза всплытия. Идёт процесс обхода DOM снизу вверх для определения, есть ли события у родительских элементов и работая с ними.
Тогда, возникает необходимость в двух вещах — обрабатывать событие и где‑то его хранить. Но, где?
Если отойти немного назад, то надо вспомнить о том, что DOM элемент является, можно сказать, объектом со своими свойствами. У него есть текст, у него есть следующий элемент и предыдущий и т. д. Так вот, что если функцию хранить в самом элементе (объекте) DOM? Это сразу решает две проблемы: как понять, «на что вызывать функцию?» и «где её хранить?».
То-есть, грубо говоря, как это выглядит:
<div></div>["клик"] = функция;
Соглашусь, что это выглядит странно, но, если получить элемент через getElementById
, к примеру, и вывести его в консоль как объект, то действительно, это будет выглядеть как‑то так, что мы присвоили свойство тегу в HTML (понятное дело, что элементу в DOM) со значением функции.
Так вот, остаётся вторая проблема, а как, собственно, обрабатывать событие клика зная, что у нас в DOM элементе есть функция. Это тоже достаточно интересный вопрос, но реализация связана с делегированием.
То-есть, что такое делегирование. Представим, что на странице будет 1000 одинаковых блоков, так вот, вместо того, чтобы присваивать 1000 блокам addEventListener
, можно сделать обобщающий момент по event.target
, допустим, общий атрибут, и, если он соответствует условию, то вызовется функция.
Возникает тогда вопрос, а куда ставить функцию, если на Element
в DOM будет не очень? Тут есть тоже достаточно крутое решение. Можно поставить обработку события прямо на document
или на объект window
, а в свойствах принимать target
, по которому кликнули. Как это будет выглядеть в теории в javascript:
document.addEventListener("click", (e)=>{if(e.target...){...}});
Таким образом, есть функция, которая срабатывает, когда кликается на элемент в document
, а есть место, куда кликается. Так вот, это место клика как раз может являться объектом DOM, в который было вложено свойство с функцией срабатывания.
К примеру, в Cample.js, обработка будет выглядеть следующим образом:
const newEach = each("new-each",
()=>["val"],
`<div id="el" :click="{{importedData.fn(data)}}"
key="{{index}}">{{data}}</div>`
);
Для элемента div
с id
«el», будет присвоена функция, которая приходит из импортированных данных. Если по документу будет кликнуто мышкой, тогда данная функция будет вызвана.
Также, для того, чтобы работать в виртуальном DOM в некоторых фреймворках, addEventListener
недостаточен, тогда, опять же, тут действуют синтетические события.
Фаза всплытия при таком подходе будет выглядеть как цикл while
или рекурсивная функция в конечном счёте которые своей работой доходят до верха DOM путём проверки parentNode
или host
Элемента.
Примерно так, будет выглядеть синтетическая обработка события клик в современных фреймворках.
Всем большое спасибо за прочтение данной статьи!
P.S. Очень благодарю всех комментаторов за способствование исправления старых ошибок в статье! Статья будет обновляться, если что-то не соответствует реалиям!