Определение своих событий

Последнее обновление: 30.10.2023

Возможность программной генерации событий открывает нам путь к созданию кастомных событий - мы можем определять и вызывать произвольные события.

Например, у нас есть функция-конструктор Account, которая принимает коичество денег и создает условный денежный счет:

function Account(money) {
    _money = money;
    this.pay=function(sum){
        if(_money >= sum){
            _money -= sum;
            console.log(_money);
        }
    }
}

В переменной _money хранится текущее количество денег на счете. С помощью функции pay условно тратим определенную сумму, если баланс позволяет. Но, допустим, нам надо как-то извещать систему, что произошло списание со счета. С одно стороны, мы могли бы это делать непосредственно в методе pay - вызывать в методе console.log() и выводить на консоль какой-то текст. Но на момент написания этого кода мы можем быть не уверены, какой именно текст надо выводить на консоль. А может быть потребуется и не на консоль, а в окне браузере. Или посылать извещение на определенный сетевой ресурс. А может наша функция-конструктор будет использоваться в Node.js, где может потребоваться какая-то другая обработка. Да и использовать нашу функцию-конструктор могут совсем другие разработчики, у которых может быть собственно понимание того, что надо делать при списании средств. В любом случае мы сталкиваемся с многовариантностью, но во всех этих ситуация главное, что нам надо сделать - уведомить систему, что произошло списание средств. И охватить все эти ситуации нам поможет определение собственных событий.

Для определения кастомных событий мы можем применять конструктор Event, в который передается название события. Так, рассмотрим следующую программу:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>METANIT.COM</title>
</head>
<body>
    <button id="btn">Pay</button>
    <script>
    const button = document.getElementById("btn");
    const myAcc = new Account(100); // условный денежный счет
    // устанавливаем обработчик события payment для всего документа
    document.addEventListener("payment", ()=>console.log("Payment succeeded!"));

    // по нажатию на кнопку выполняем метод pay
    button.addEventListener("click", ()=>myAcc.pay(50));
    // конструктор объекта счета
    function Account(money) {
        _money = money;
        this.pay=function(sum){
            if(_money >= sum){
                _money -= sum;
                console.log(_money);

                const event = new Event("payment"); // определяем объект события
                document.dispatchEvent(event);      // генерируем событие для всего документа
            }
        }
    }
    </script>
</body>
</html>

Основные моменты. В методе pay создаем объект Event, которое будет представлять событие "payment" (не важно, что такого события изначально не существует, мы сами его создаем). Затем генерируем это событие:

const event = new Event("payment"); // определяем объект события
document.dispatchEvent(event);      // генерируем событие для всего документа

Стоит отметить, что событие генерируется для всего документа: document.dispatchEvent(event), но это может быть любой конкретный элемент веб-страницы.

Чтобы обработать это событие, подписываемся на него:

document.addEventListener("payment", ()=>console.log("Payment succeeded!"));

Опять же подписка на событие производится для всего документа. Обработчик события просто выводит строку на консоль.

По нажатию на кнопку вызываем метод pay объекта myAcc и тем самым генерируем событие "payment" (если на счете достаточно средств).

Для тестирования понажимаем на кнопку:

Создание своих событий в JavaScript

Также, как и в общем случае, мы можем получить объект подобное события в обработчике:

// получаем через параметр e объект события
document.addEventListener("payment", (e)=>{
    console.log(e.type);                //  payment
    console.log("Payment succeeded!");
});

CustomEvent

Однако тип Event хотя и может использоваться, но не очень подходит для определения кастомных событий. Например, что, если мы хотим передать в обработчик события какую-то дополнительную информацию - сумму списания, текущий баланс или что-то еще? И для подобных случаев лучше использовать тип CustomEvent. Так, изменим код JavaScript следующим образом:

const button = document.getElementById("btn");
document.addEventListener("payment", (e)=>{
    console.log("Payment succeeded!");
    console.log("Payment Sum:", e.detail.paymentSum);   // получаем данные события
    console.log("Current balance:", e.detail.balance);
});

const myAcc = new Account(100);
// по нажатию на кнопку выполняем метод pay
button.addEventListener("click", ()=>myAcc.pay(50));

function Account(money) {
    _money = money;
    this.pay=function(sum){
        if(_money >= sum){
            _money -= sum;
            // определяем объект события
            const event = new CustomEvent("payment", {
                detail:{                //  передаем в CustomEvent данные о событии
                    paymentSum: sum, 
                    balance: _money
                }
            });
            document.dispatchEvent(event);      // генерируем событие для всего документа
        }
    }
}

В CustomEvent в качестве второго параметра передается конфигурационный объект, который имеет свойство detail. Это свойство в свою очередь представляет объект с произвольным набором свойств. В данном случае мы определяем в нем свойства paymentSum и balance и передаем этим свойствам интересующие нас значения:

const event = new CustomEvent("payment", {
    detail:{
        paymentSum: sum, 
        balance: _money
    }
});

Далее передаем объект CustomEvent (как и Event) в dispatchEvent и тем самым генерируем событие:

document.dispatchEvent(event);

При обработке события мы можем получить переданные данные через свойство detail:

document.addEventListener("payment", (e)=>{
    console.log("Payment succeeded!");
    console.log("Payment Sum:", e.detail.paymentSum);   // получаем данные события
    console.log("Current balance:", e.detail.balance);
});

Пример консольного вывода при первом нажатии кнопки:

Payment succeeded!
Payment Sum: 50
Current balance: 50

Подобным образом можно определять и другие события. Например, определим еще одно событие на случай, если средств недостаточно для совершения платежа:

const button = document.getElementById("btn");
document.addEventListener("payment_success", (e)=>{
    console.log("Payment succeeded!");
    console.log("Payment Sum:", e.detail.paymentSum);
    console.log("Current balance:", e.detail.balance);
});
document.addEventListener("payment_fail", (e)=>{
    console.error("Payment failed");
    console.error("Current balance:", e.detail.balance, "Requested Sum: ", e.detail.paymentSum);
});
const myAcc = new Account(100); 
button.addEventListener("click", ()=>myAcc.pay(50));

function Account(money) {
    _money = money;
    this.pay=function(sum){
        const data = { 
            paymentSum: sum, 
            balance: _money
        };
        if(_money >= sum){
            _money -= sum;

            const event = new CustomEvent("payment_success", {
                detail: data
            });
            document.dispatchEvent(event);
        }
        else{
            const event = new CustomEvent("payment_fail", {
                detail: data
            });
            document.dispatchEvent(event);
        }
    }
}

Теперь, если средст достаточно на счете генерируется событие "payment_success", а если недостаточно - то "payment_fail". И для каждого из этих событий определяем свой обработчик.

консольный вывод программы (при трех нажатиях на кнопку):

Payment succeeded!
Payment Sum: 50
Current balance: 100
Payment succeeded!
Payment Sum: 50
Current balance: 50
Payment failed
Current balance: 0 Requested Sum:  50
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850