События

Событие и обработчик события

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

Записываем обработчик события. Устаревшие способы.

Есть 3 способа записать обработчик событий. Разберем первые два, они не очень рекомендуются к использованию.

Напрямую в html

// записываем тегу button событие click с приставкой on и в ковычках пишем js код.
<button onclick="console.log('я дима')" class="btn">я не дима </button>
// При нажатии на эту кнопку в консоль будет выводить текст - это и есть наш обработчик

Использовать свойства DOM дерева

// Сначала нам нужен элемент
const btn = document.querySelector('button');

btn.onclick = function () { // обращаемся к нашему элементу и в свойство onclick записываем функцию
    console.log('hello');
};

Если у вас большой код и вы назначали обработчик, а потом забыли, что взаимодействовали с этим элементом и назначали обработчик еще раз:

 // - этот второй раз перезапишет первый обработчик и вы просто потеряете функционал
btn.onclick = function () {
    console.log('hello world');
};

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

Записываем обработчик события правильно addEventListener()

Обработчик события addEventListener имеет 3 аргумента.
1 - событие(название события)
2 - колбек функция.
3 - Это опция события, но об этом позже.

const btn = document.querySelector('button');
btn.addEventListener('click', () => {  // 'click' - первый наш аргумент, событие клика мыши. 
    console.log('Hello Dima');
}); // В общем js следит за этим элементом btn.addEventListener и если произошло событие нами написанное
// то срабатывает колбек функция(как мы помним, колбек функции выполняются строго за другими) в нашем случае после события. 
// Если мы навесим еще один обработчик, то он не перезапишет предыдущий.
btn.addEventListener('click', () => {
    console.log('Hello SEREGA'); // Наше действие не перезапишет предыдущее, они сработают по порядку
});
// События в js выполняются в порядке очереди!
alt text

Объект event

Иногда нам нужно получать данные о том элементе с которым мы взаимодействуем, для этого у нас есть специальный объект event, этот объект передается как аргумент в колбек функцию (называть можем как угодно, но обычно это event или e).

const btn = document.querySelector('button');
btn.addEventListener('click', (event) => {
    console.log(event); // и мы получим MouseEvent {isTrusted: true, screenX: 360, screenY: 697, clientX: 196, clientY: 511, …}
    // это объект который описывает, что произошло с элементом. Внутри очень много всего, но самые важные свойства это: 

        // type: "click" - это то какое событие у нас произошло в нашем случае это клик
        // target: button.btn - это тот элемент на котором произошло событие
    
    // Например можем удалить наш элемент.
    // мы обращаемся к к объекту event и к свойству target в котором помещается элемент с которым мы взаимодействуем.
    event.target.remove(); // при нажатии элемент удаляется.
});

Удаляем обработчик события removeEventListener()

removeEventListener() - удаляет обработчик события зарегистрированный ранее с помощью метода addEventListener().

let i = 0;
const btn = document.querySelector('button');

// Для того, что бы удалить обрабочик события, нам нужно ссылаться на одинаковые функции.
const showElement = (event) => { // Создаем нашу функцию в переменной.
    console.log(event.target); // выводим в консоль наш элемент.
    i++
    if (i == 1) { // пишем условие, что если i равна 1 
        btn.removeEventListener('click', showElement); // то мы удаляем наш обработчик события(ссылаемся на одну функцию)
    }
};
btn.addEventListener('click', showElement); // Передаем в обработчик ссылку на функцию вторым аргументом.
// При нажатии на кнопку наша кнопка выведется в консоли, i станет равна 1 и удалит обработчик, последующие нажатия уже не дадут никакого результата.
// если бы я написал внутри каждого обработчика одинаковые функции они бы не были равны, это все равно было бы два разных объекта, поэтому просто ссылаемся на одну функцию!

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

Всплытие событий - это когда обработчик события сначала срабатывает на самом вложенном элементе, затем на родителе если он есть и так выше и выше по иерархии.

const btn = document.querySelector('.btn'); // получаем кнопку
const overlay = document.querySelector('.overlay'); // родитель кнопки
const showElement = (event) => { 
    console.log(event.target); // выводим в консоль наш элемент.
    console.log(event.type); // выводим тип события

};
 // родитель и ребенок делают одно и тоже событие.
overlay.addEventListener('click', showElement);
btn.addEventListener('click', showElement);

При нажатии на кнопку мы получим такую картину:

alt text

Сначала обработчик срабатывает на элементе вложеннее, а после по иерархии вверх, в нашем случае кнопка и div в котором она находится - это и называется всплытие событий. Мы можем немного изменить такое поведение с помощью свойства currentTurget.

currentTarget

currentTarget - используется, когда один и тот же обработчик события присваивается нескольким элементам ( target использует сам элемент, а currentTarget - его родителя) Если в коде выше мы поменяем target на currentTarget, то получим более наглядный пример.

alt text

Теперь мы наглядно получаем вторым элементом родителя.

Отмена стандартного поведения браузера preventDefault()

preventDefault() - это метод у объекта события, нашего event, он отменяет стандартное поведение браузера.

const link = document.querySelector('a'); // получаем ссылку. Эта ссылка ведет на мой гитХаб

link.addEventListener('click', (e)=> { // вещаем на нее оброботчик события
    e.preventDefault(); // используем preventDefault на объекте event.
    // теперь при нажатии на ссылку, ничего не будет происходить, мы отменили стандартное поведение браузера.
})

Перебираем обработчики и вешаем несколько одинаковых на элементы - (forEach)

Получить все кнопки например через querySelectorAll('button') и потом повесить обработчик на это, не получится, так как метод querySelectorAll даст нам псевдомассив, а у него нет метода addEventListener.
Для этого нужно этот псевдомассив перебрать и на каждый элемент повесить обработчик

const btns = document.querySelectorAll('button');

btns.forEach((btn) => { // используем на нашем псевдомассиве forEach, В первом аргументе как мы помним находится элемент который перебераем
    btn.addEventListener('click', (e) => { // далее на каждый перебераемый элемент мы вешаем обработчик событий
        console.log(e.target); // и все
    });
});

Опции события

у addEventListener - есть третий аргумент - это опции (Объект options, который определяет характеристики объекта, прослушивающего событие) Например once указывает, что обработчик должен быть вызван не более одного раза после добавления.

addEventListener('click', тут событие,{once:true});

Есть несколько таких опций, их все можно загуглить.

  • click - происходит, когда кликнули на элемент левой кнопкой мыши (на устройствах с сенсорными экранами оно происходит при касании).
  • mouseover / mouseout – когда мышь наводится на элемент / или покидает элемент.
  • mousedown / mouseup – когда нажали / отжали кнопку мыши на элементе.
  • mousemove – при движении мыши.
  • mouseenter - при наведении мыши на элемент
  • submit - нужен для отправки формы.