Как сгенерировать событие c
Перейти к содержимому

Как сгенерировать событие c

  • автор:

Как сгенерировать событие c

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

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

class Account < // сумма на счете public int Sum < get; private set; >// в конструкторе устанавливаем начальную сумму на счете public Account(int sum) => Sum = sum; // добавление средств на счет public void Put(int sum) => Sum += sum; // списание средств со счета public void Take(int sum) < if (Sum >= sum) < Sum -= sum; >> >

В конструкторе устанавливаем начальную сумму, которая хранится в свойстве Sum. С помощью метода Put мы можем добавить средства на счет, а с помощью метода Take, наоборот, снять деньги со счета. Попробуем использовать класс в программе — создать счет, положить и снять с него деньги:

Account account = new Account(100); account.Put(20); // добавляем на счет 20 Console.WriteLine($"Сумма на счете: "); account.Take(70); // пытаемся снять со счета 70 Console.WriteLine($"Сумма на счете: "); account.Take(180); // пытаемся снять со счета 180 Console.WriteLine($"Сумма на счете: ");
Сумма на счете: 120 Сумма на счете: 50 Сумма на счете: 50

Все операции работают как и положено. Но что если мы хотим уведомлять пользователя о результатах его операций. Мы могли бы, например, для этого изменить метод Put следующим образом:

public void Put(int sum) < Sum += sum; Console.WriteLine($"На счет поступило: "); >

Казалось, теперь мы будем извещены об операции, увидев соответствующее сообщение на консоли. Но тут есть ряд замечаний. На момент определения класса мы можем точно не знать, какое действие мы хотим произвести в методе Put в ответ на добавление денег. Это может вывод на консоль, а может быть мы захотим уведомить пользователя по email или sms. Более того мы можем создать отдельную библиотеку классов, которая будет содержать этот класс, и добавлять ее в другие проекты. И уже из этих проектов решать, какое действие должно выполняться. Возможно, мы захотим использовать класс Account в графическом приложении и выводить при добавлении на счет в графическом сообщении, а не консоль. Или нашу библиотеку классов будет использовать другой разработчик, у которого свое мнение, что именно делать при добавлении на счет. И все эти вопросы мы можем решить, используя события.

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

События объявляются в классе с помощью ключевого слова event , после которого указывается тип делегата, который представляет событие:

delegate void AccountHandler(string message); event AccountHandler Notify;

В данном случае вначале определяется делегат AccountHandler, который принимает один параметр типа string. Затем с помощью ключевого слова event определяется событие с именем Notify, которое представляет делегат AccountHandler. Название для события может быть произвольным, но в любом случае оно должно представлять некоторый делегат.

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

Notify("Произошло действие");

Поскольку событие Notify представляет делегат AccountHandler, который принимает один параметр типа string — строку, то при вызове события нам надо передать в него строку.

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

if(Notify !=null) Notify("Произошло действие");
Notify?.Invoke("Произошло действие");

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

Объединим все вместе и создадим и вызовем событие:

class Account < public delegate void AccountHandler(string message); public event AccountHandler? Notify; // 1.Определение события public Account(int sum) =>Sum = sum; public int Sum < get; private set; >public void Put(int sum) < Sum += sum; Notify?.Invoke($"На счет поступило: "); // 2.Вызов события > public void Take(int sum) < if (Sum >= sum) < Sum -= sum; Notify?.Invoke($"Со счета снято: "); // 2.Вызов события > else < Notify?.Invoke($"Недостаточно денег на счете. Текущий баланс: "); ; > > >

Теперь с помощью события Notify мы уведомляем систему о том, что были добавлены средства и о том, что средства сняты со счета или на счете недостаточно средств.

Добавление обработчика события

С событием может быть связан один или несколько обработчиков. Обработчики событий — это именно то, что выполняется при вызове событий. Нередко в качестве обработчиков событий применяются методы. Каждый обработчик событий по списку параметров и возвращаемому типу должен соответствовать делегату, который представляет событие. Для добавления обработчика события применяется операция += :

Notify += обработчик события;

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

Account account = new Account(100); account.Notify += DisplayMessage; // Добавляем обработчик для события Notify account.Put(20); // добавляем на счет 20 Console.WriteLine($"Сумма на счете: "); account.Take(70); // пытаемся снять со счета 70 Console.WriteLine($"Сумма на счете: "); account.Take(180); // пытаемся снять со счета 180 Console.WriteLine($"Сумма на счете: "); void DisplayMessage(string message) => Console.WriteLine(message);

В данном случае в качестве обработчика используется метод DisplayMessage, который соответствует по списку параметров и возвращаемому типу делегату AccountHandler. В итоге при вызове события Notify?.Invoke() будет вызываться метод DisplayMessage, которому для параметра message будет передаваться строка, которая передается в Notify?.Invoke() . В DisplayMessage просто выводим полученное от события сообщение, но можно было бы определить любую логику.

Если бы в данном случае обработчик не был бы установлен, то при вызове события Notify?.Invoke() ничего не происходило, так как событие Notify было бы равно null.

Консольный вывод программы:

На счет поступило: 20 Сумма на счете: 120 Со счета снято: 70 Сумма на счете: 50 Недостаточно денег на счете. Текущий баланс: 50 Сумма на счете: 50

Теперь мы можем выделить класс Account в отдельную библиотеку классов и добавлять в любой проект.

Добавление и удаление обработчиков

Для одного события можно установить несколько обработчиков и потом в любой момент времени их удалить. Для удаления обработчиков применяется операция -= . Например:

Account account = new Account(100); account.Notify += DisplayMessage; // добавляем обработчик DisplayMessage account.Notify += DisplayRedMessage; // добавляем обработчик DisplayRedMessage account.Put(20); // добавляем на счет 20 account.Notify -= DisplayRedMessage; // удаляем обработчик DisplayRedMessage account.Put(50); // добавляем на счет 50 void DisplayMessage(string message) => Console.WriteLine(message); void DisplayRedMessage(string message) < // Устанавливаем красный цвет символов Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(message); // Сбрасываем настройки цвета Console.ResetColor(); >
На счет поступило: 20 На счет поступило: 20 На счет поступило: 50

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

Account acc = new Account(100); // установка делегата, который указывает на метод DisplayMessage acc.Notify += new Account.AccountHandler(DisplayMessage); // установка в качестве обработчика метода DisplayMessage acc.Notify += DisplayMessage; // добавляем обработчик DisplayMessage acc.Put(20); // добавляем на счет 20 void DisplayMessage(string message) => Console.WriteLine(message);

В данном случае разницы между двумя обработчиками никакой не будет.

Установка в качестве обработчика анонимного метода:

Account acc = new Account(100); acc.Notify += delegate (string mes) < Console.WriteLine(mes); >; acc.Put(20);

Установка в качестве обработчика лямбда-выражения:

Account account = new Account(100); account.Notify += message => Console.WriteLine(message); account.Put(20);

Управление обработчиками

С помощью специальных акссесоров add/remove мы можем управлять добавлением и удалением обработчиков. Как правило, подобная функциональность редко требуется, но тем не менее мы ее можем использовать. Например:

class Account < public delegate void AccountHandler(string message); AccountHandler? notify; public event AccountHandler Notify < add < notify += value; Console.WriteLine($"добавлен"); > remove < notify -= value; Console.WriteLine($"удален"); > > public Account(int sum) => Sum = sum; public int Sum < get; private set; >public void Put(int sum) < Sum += sum; notify?.Invoke($"На счет поступило: "); // 2.Вызов события > public void Take(int sum) < if (Sum >= sum) < Sum -= sum; notify?.Invoke($"Со счета снято: "); // 2.Вызов события > else < notify?.Invoke($"Недостаточно денег на счете. Текущий баланс: "); ; > > >

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

AccountHandler notify;

Во второй части определяем акссесоры add и remove. Аксессор add вызывается при добавлении обработчика, то есть при операции +=. Добавляемый обработчик доступен через ключевое слово value . Здесь мы можем получить информацию об обработчике (например, имя метода через value.Method.Name) и определить некоторую логику. В данном случае для простоты просто выводится сообщение на консоль:

add < notify += value; Console.WriteLine($"добавлен"); >

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

remove < notify -= value; Console.WriteLine($"удален"); >

Внутри класса событие вызывается также через переменную notify. Но для добавления и удаления обработчиков в программе используется как раз Notify:

Account acc = new Account(100); acc.Notify += DisplayMessage; // добавляем обработчик DisplayMessage acc.Put(20); // добавляем на счет 20 acc.Notify -= DisplayMessage; // удаляем обработчик DisplayMessage acc.Put(20); // добавляем на счет 20 void DisplayMessage(string message) => Console.WriteLine(message);

Консольный вывод программы:

DisplayMessage добавлен На счет поступило: 20 DisplayMessage удален

Передача данных события

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

class AccountEventArgs < // Сообщение public string Message// Сумма, на которую изменился счет public int Sum public AccountEventArgs(string message, int sum) < Message = message; Sum = sum; >>

Данный класс имеет два свойства: Message — для хранения выводимого сообщения и Sum — для хранения суммы, на которую изменился счет.

Теперь применим класс AccoutEventArgs, изменив класс Account следующим образом:

class Account < public delegate void AccountHandler(Account sender, AccountEventArgs e); public event AccountHandler? Notify; public int Sum < get; private set; >public Account(int sum) => Sum = sum; public void Put(int sum) < Sum += sum; Notify?.Invoke(this, new AccountEventArgs($"На счет поступило ", sum)); > public void Take(int sum) < if (Sum >= sum) < Sum -= sum; Notify?.Invoke(this, new AccountEventArgs($"Сумма снята со счета", sum)); > else < Notify?.Invoke(this, new AccountEventArgs("Недостаточно денег на счете", sum)); >> >

По сравнению с предыдущей версией класса Account здесь изменилось только количество параметров у делегата и соответственно количество параметров при вызове события. Теперь делегат AccountHandler в качестве первого параметра принимает объект, который вызвал событие, то есть текущий объект Account. А в качестве второго параметра принимает объект AccountEventArgs, который хранит информацию о событии, получаемую через конструктор.

Теперь изменим основную программу:

Account acc = new Account(100); acc.Notify += DisplayMessage; acc.Put(20); acc.Take(70); acc.Take(150); void DisplayMessage(Account sender, AccountEventArgs e) < Console.WriteLine($"Сумма транзакции: "); Console.WriteLine(e.Message); Console.WriteLine($"Текущая сумма на счете: "); >

По сравнению с предыдущим вариантом здесь мы только изменяем количество параметров и их использования в обработчике DisplayMessage. Благодаря первому параметру в методе можно получить информацию об отправителе события — счете, с которым производится операция. А через второй параметр можно получить инфомацию о состоянии операции.

Генерация пользовательских событий

Можно не только назначать обработчики, но и генерировать события из JavaScript-кода.

Пользовательские события могут быть использованы при создании графических компонентов. Например, корневой элемент нашего меню, реализованного при помощи JavaScript, может генерировать события, относящиеся к этому меню: open (меню раскрыто), select (выбран пункт меню) и т.п. А другой код может слушать эти события и узнавать, что происходит с меню.

Можно генерировать не только совершенно новые, придуманные нами события, но и встроенные, такие как click , mousedown и другие. Это бывает полезно для автоматического тестирования.

Конструктор Event

Встроенные классы для событий формируют иерархию аналогично классам для DOM-элементов. Её корнем является встроенный класс Event.

Событие встроенного класса Event можно создать так:

let event = new Event(type[, options]);
  • type – тип события, строка, например «click» или же любой придуманный нами – «my-event» .
  • options – объект с тремя необязательными свойствами:
    • bubbles: true/false – если true , тогда событие всплывает.
    • cancelable: true/false – если true , тогда можно отменить действие по умолчанию. Позже мы разберём, что это значит для пользовательских событий.
    • composed: true/false – если true , тогда событие будет всплывать наружу за пределы Shadow DOM. Позже мы разберём это в разделе Веб-компоненты.

    По умолчанию все три свойства установлены в false: .

    Метод dispatchEvent

    После того, как объект события создан, мы должны запустить его на элементе, вызвав метод elem.dispatchEvent(event) .

    Затем обработчики отреагируют на него, как будто это обычное браузерное событие. Если при создании указан флаг bubbles , то оно будет всплывать.

    В примере ниже событие click инициируется JavaScript-кодом так, как будто кликнули по кнопке:

      

    event.isTrusted

    Можно легко отличить «настоящее» событие от сгенерированного кодом.

    Свойство event.isTrusted принимает значение true для событий, порождаемых реальными действиями пользователя, и false для генерируемых кодом.

    Пример всплытия

    Мы можем создать всплывающее событие с именем «hello» и поймать его на document .

    Всё, что нужно сделать – это установить флаг bubbles в true :

     

    1. Мы должны использовать addEventListener для наших собственных событий, т.к. on -свойства существуют только для встроенных событий, то есть document.onhello не сработает.
    2. Мы обязаны передать флаг bubbles:true , иначе наше событие не будет всплывать.

    Механизм всплытия идентичен как для встроенного события ( click ), так и для пользовательского события ( hello ). Также одинакова работа фаз всплытия и погружения.

    MouseEvent, KeyboardEvent и другие

    Для некоторых конкретных типов событий есть свои специфические конструкторы. Вот небольшой список конструкторов для различных событий пользовательского интерфейса, которые можно найти в спецификации UI Event:

    • UIEvent
    • FocusEvent
    • MouseEvent
    • WheelEvent
    • KeyboardEvent

    Стоит использовать их вместо new Event , если мы хотим создавать такие события. К примеру, new MouseEvent(«click») .

    Специфический конструктор позволяет указать стандартные свойства для данного типа события.

    Например, clientX/clientY для события мыши:

    let event = new MouseEvent("click", < bubbles: true, cancelable: true, clientX: 100, clientY: 100 >); alert(event.clientX); // 100

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

    let event = new Event("click", < bubbles: true, // только свойства bubbles и cancelable cancelable: true, // работают в конструкторе Event clientX: 100, clientY: 100 >); alert(event.clientX); // undefined, неизвестное свойство проигнорировано!

    Впрочем, использование конкретного конструктора не является обязательным, можно обойтись Event , а свойства записать в объект отдельно, после создания, вот так: event.clientX=100 . Здесь это скорее вопрос удобства и желания следовать правилам. События, которые генерирует браузер, всегда имеют правильный тип.

    Полный список свойств по типам событий вы найдёте в спецификации, например, MouseEvent.

    Пользовательские события

    Для генерации событий совершенно новых типов, таких как «hello» , следует использовать конструктор new CustomEvent . Технически CustomEvent абсолютно идентичен Event за исключением одной небольшой детали.

    У второго аргумента-объекта есть дополнительное свойство detail , в котором можно указывать информацию для передачи в событие.

     

    Свойство detail может содержать любые данные. Надо сказать, что никто не мешает и в обычное new Event записать любые свойства. Но CustomEvent предоставляет специальное поле detail во избежание конфликтов с другими свойствами события.

    Кроме того, класс события описывает, что это за событие, и если оно не браузерное, а пользовательское, то лучше использовать CustomEvent , чтобы явно об этом сказать.

    event.preventDefault()

    Для многих браузерных событий есть «действия по умолчанию», такие как переход по ссылке, выделение и т.п.

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

    Вызов event.preventDefault() является возможностью для обработчика события сообщить в сгенерировавший событие код, что эти действия надо отменить.

    Тогда вызов elem.dispatchEvent(event) возвратит false . И код, сгенерировавший событие, узнает, что продолжать не нужно.

    Посмотрим практический пример – прячущегося кролика (могло бы быть скрывающееся меню или что-то ещё).

    Ниже вы можете видеть кролика #rabbit и функцию hide() , которая при вызове генерирует на нём событие «hide» , уведомляя всех интересующихся, что кролик собирается спрятаться.

    Любой обработчик может узнать об этом, подписавшись на событие hide через rabbit.addEventListener(‘hide’. ) и, при желании, отменить действие по умолчанию через event.preventDefault() . Тогда кролик не исчезнет:

    o<>

    Обратите внимание: событие должно содержать флаг cancelable: true . Иначе, вызов event.preventDefault() будет проигнорирован.

    Вложенные события обрабатываются синхронно

    Обычно события обрабатываются асинхронно. То есть, если браузер обрабатывает onclick и в процессе этого произойдёт новое событие, то оно ждёт, пока закончится обработка onclick .

    Исключением является ситуация, когда событие инициировано из обработчика другого события.

    Тогда управление сначала переходит в обработчик вложенного события и уже после этого возвращается назад.

    В примере ниже событие menu-open обрабатывается синхронно во время обработки onclick :

     

    Порядок вывода: 1 → вложенное событие → 2.

    Обратите внимание, что вложенное событие menu-open успевает всплыть и запустить обработчик на document . Обработка вложенного события полностью завершается до того, как управление возвращается во внешний код ( onclick ).

    Это справедливо не только для dispatchEvent , но и для других ситуаций. JavaScript в обработчике события может вызвать другие методы, которые приведут к другим событиям – они тоже обрабатываются синхронно.

    Если нам это не подходит, то мы можем либо поместить dispatchEvent (или любой другой код, инициирующий события) в конец обработчика onclick , либо, если это неудобно, можно обернуть генерацию события в setTimeout с нулевой задержкой:

     

    Теперь dispatchEvent запускается асинхронно после исполнения текущего кода, включая mouse.onclick , поэтому обработчики полностью независимы.

    Новый порядок вывода: 1 → 2 → вложенное событие.

    Итого

    Чтобы сгенерировать событие из кода, вначале надо создать объект события.

    Базовый конструктор Event(name, options) принимает обязательное имя события и options – объект с двумя свойствами:

    • bubbles: true чтобы событие всплывало.
    • cancelable: true если мы хотим, чтобы event.preventDefault() работал.

    Особые конструкторы встроенных событий MouseEvent , KeyboardEvent и другие принимают специфичные для каждого конкретного типа событий свойства. Например, clientX для событий мыши.

    Для пользовательских событий стоит применять конструктор CustomEvent . У него есть дополнительная опция detail , с помощью которой можно передавать информацию в объекте события. После чего все обработчики смогут получить к ней доступ через event.detail .

    Несмотря на техническую возможность генерировать встроенные браузерные события типа click или keydown , пользоваться ей стоит с большой осторожностью.

    Весьма часто, когда разработчик хочет сгенерировать встроенное событие – это вызвано «кривой» архитектурой кода.

    Как правило, генерация встроенных событий полезна в следующих случаях:

    • Либо как явный и грубый хак, чтобы заставить работать сторонние библиотеки, в которых не предусмотрены другие средства взаимодействия.
    • Либо для автоматического тестирования, чтобы скриптом «нажать на кнопку» и посмотреть, произошло ли нужное действие.

    Пользовательские события со своими именами часто создают для улучшения архитектуры, чтобы сообщить о том, что происходит внутри наших меню, слайдеров, каруселей и т.д.

    Как вызвать событие вручную или как имитировать нажатие на кнопку

    Есть форма, на ней userControl который прилетает по dll, после выбора продукта с userControl, открываеться другая форма с дополнительными параметрами( у меня нет доступа к этой форме), на ней нажимаем кнопку принять, форма закрывается, мы выходим из функции. Теперь мне нужно запустить другую функцию в этом же классе, можно запустить ее через нажатие на кнопку в первой форме, но мне нужно что бы эта функция запускалась автоматически. Тоесть нужно вызвать событие вручную .Как это сделать?

    public partial class CatalogPaletteControl : UserControl < public CatalogPaletteControl() < InitializeComponent(); >private void CatalogPaletteControl_Load(object sender, EventArgs e) < >private void button1_Click(object sender, EventArgs e) < //do something >> 

    После загрузки CatalogPaletteControl_Load поток заканчиваеться, тоесть ничего больше не происходит. Где вызывать button1_Click(null,null)

    Отслеживать
    задан 28 мая 2019 в 15:16
    11 1 1 серебряный знак 2 2 бронзовых знака
    Button_Click(name_of_button, new EventArgs())?
    28 мая 2019 в 15:28
    Вот как его вызвать не нажимая кнопки
    28 мая 2019 в 15:40
    WinForms? Поставьте метку.
    28 мая 2019 в 16:11
    Вы знаете как вызвать любой метод? Обработчик события — тот же метод.
    28 мая 2019 в 16:11

    1 ответ 1

    Сортировка: Сброс на вариант по умолчанию

    Обработчик события — это обычный метод. И вызвать его можно самым обычным способом.

    Допустим, имеется такой метод-обработчик нажатия на кнопку

    private void SomeButton_Click(object sender, EventArgs e) < // some code >
    SomeButton_Click(null, null); 

    Здесь в качестве параметров передаются null .

    Если в обработчике нужно знать, какая именно кнопка вызвала его, плюс нужно определённое значение аргументов события, то вызываем метод с параметрами:

    SomeButton_Click(someButton, EventArgs.Empty); 

    Второй параметр можно явно создать: new EventArgs() .

    У класса Button есть метод PerformClick, можно использовать его:

    someButton.PerformClick(); 

    Ещё один вариант, вынести в отдельный метод код, содержащийся в обработчике события:

    private void SomeButton_Click(object sender, EventArgs e) < DoWork(); >private void DoWork() < // some code >

    И вызывать этот метод там, где нужно:

    DoWork(); 

    Естественно, добавляем параметры, если они нужны.

    Этот способ более правильный с точки зрения архитектуры: отделяем код бизнес-логики от GUI.

    Метод EventTarget.addEventListener()

    Метод EventTarget.addEventListener() регистрирует определённый обработчик события, вызванного на EventTarget .

    EventTarget может быть Element , Document , Window , или любым другим объектом, поддерживающим события (таким как XMLHttpRequest (en-US) ).

    Синтаксис

    target.addEventListener(type, listener[, options]); target.addEventListener(type, listener[, useCapture]); target.addEventListener(type, listener[, useCapture, wantsUntrusted Non-standard ]); // только Gecko/Mozilla

    Параметры

    Объект, который принимает уведомление, когда событие указанного типа произошло. Это должен быть объект, реализующий интерфейс EventListener или просто функция JavaScript.

    Объект options , который определяет характеристики объекта, прослушивающего событие. Доступны следующие варианты:

    • capture : Boolean указывает, что события этого типа будут отправлены зарегистрированному обработчику listener перед отправкой на EventTarget , расположенный ниже в дереве DOM.
    • once : Boolean указывает, что обработчик должен быть вызван не более одного раза после добавления. Если true , обработчик автоматически удаляется при вызове.
    • passive : Boolean указывает, что обработчик никогда не вызовет preventDefault() . Если всё же вызов будет произведён, браузер должен игнорировать его и генерировать консольное предупреждение. Пример Улучшение производительности прокрутки с помощью passive true
    • Non-standard mozSystemGroup : Boolean указывает, что обработчик должен быть добавлен в системную группу. Доступно только в коде, запущенном в XBL или в расширении Chrome.

    Если равно true , useCapture указывает, что пользователь желает начать захват. После инициализации захвата все события указанного типа будут отправлены в зарегистрированный listener перед отправкой в какой-либо EventTarget под ним в дереве DOM. События, восходящие вверх по дереву, не будут вызывать обработчиков, которым назначено использовать захват. Смотрите DOM Level 3 Events для более детального объяснения. Значение useCapture по умолчанию равно false .

    Примечание: Для обработчиков событий прикреплённых к цели события, событие находиться в целевой фазе, а не в фазах захвата или всплытия. События в целевой фазе инициируют все обработчики на элементе в том порядке, в котором они были зарегистрированы независимо от параметра useCapture .

    Примечание: useCapture не всегда был опциональным. Лучше указывать данный параметр для повышения совместимости.

    wantsUntrusted Non-standard

    Если равно true , обработчик будет получать сгенерированные события, посланные со страницы (по умолчанию равно false для chrome и true для обычных веб-страниц). Этот параметр доступен только в Gecko и в основном полезен для использования в дополнениях и самом браузере. Смотрите Взаимодействие между привилегированными и непривилегированными страницами для примеров использования.

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

    Возвращаемое значение

    Примечания по использованию

    Колбэк обработчика событий

    Обработчик событий может быть задан либо как колбэк-функция, либо как объект реализующий EventListener , чей handleEvent() (en-US) метод служит как колбэк-функция.

    Сама колбэк-функция имеет те же параметры и возвращаемое значение что и метод handleEvent() ; То есть колбэк принимает единственный параметр: объект основанный на Event описывая событие, которое произошло и ничего не возвращая.

    Например, колбэк обработчика событий, который может использоваться для обработки fullscreenchange (en-US) и fullscreenerror (en-US) может выглядеть так:

    function eventHandler(event)  if (event.type == "fullscreenchange")  /* Переключатель полноэкранного режима */ > /* fullscreenerror */ else  /* Ошибка переключателя полноэкранного режима */ > > 

    Безопасная проверка поддержки option

    В более старых версиях спецификации DOM третьим параметром addEventListener было логическое значение, указывающее, следует ли захватывать событие на этапе погружения. Со временем стало ясно, что необходимо больше вариантов. Вместо добавления дополнительных параметров в функцию (усложняя ситуацию при использовании необязательных значений) третий параметр был изменён на объект, который может содержать различные свойства, определяющие значения параметров для настройки обработчика событий.

    Поскольку старые браузеры (а также некоторые не слишком старые браузеры) по-прежнему предполагают, что третий параметр является логическим, возникает необходимость создания своего кода, чтобы разумно обрабатывать этот сценарий. Вы можете сделать это, используя функцию обнаружения для каждого из интересующих вас параметров.

    Например, если вы хотите проверить параметр passive :

    var passiveSupported = false; try  var options = Object.defineProperty(>, "passive",  get: function ()  passiveSupported = true; >, >); window.addEventListener("test", null, options); > catch (err) > 

    Этот код создаёт объект options с геттером для свойства passive, устанавливающим флаг passiveSupported в true , если он вызван. Это означает, что если браузер проверяет значение свойства passive на объекте options , значение passiveSupported будет установлено в true; в противном случае он останется ложным. Затем мы вызываем addEventListener , чтобы настроить фальшивый обработчик событий, указав эти параметры для проверки опций, если браузер распознает объект в качестве третьего параметра.

    Для проверки поддержки использования какой-либо опции можно просто добавить геттер для неё, используя код, подобный тому, что показан выше.

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

    .addEventListener( "mouseup", handleMouseUp, passiveSupported ?  passive: true > : false, ); 

    Здесь мы добавляем обработчик события mouseup (en-US) элемента someElement . Для третьего параметра, если passiveSupported имеет значение true , мы указываем объект options с passive: true ; в противном случае мы знаем, что нам нужно передать логическое значение, и мы передаём false как значение параметра useCapture .

    Вы можете использовать стороннюю библиотеку, такую как Modernizr или Detect It, чтобы проверить поддержку необходимого свойства.

    Примеры

    Добавление простого обработчика

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

    HTML Содержимое
    table id="outside"> tr> td id="t1">одинtd> tr> tr> td id="t2">дваtd> tr> table> 
    JavaScript Содержимое
    // Функция изменяет содержимое t2 function modifyText()  var t2 = document.getElementById("t2"); if (t2.firstChild.nodeValue == "три")  t2.firstChild.nodeValue = "два"; > else  t2.firstChild.nodeValue = "три"; > > // Добавляет обработчика событий для таблицы var el = document.getElementById("outside"); el.addEventListener("click", modifyText, false); 

    В примере выше, modifyText() регистрирует обработчика для события click, используя addEventListener() . Клик в любом месте таблицы будет поднимать обработчик и запускать modifyText() .

    Результат

    Если вам нужно передать параметры в обработчик, вы можете использовать анонимные функции.

    Обработчик события с анонимной функцией

    HTML Содержимое
    table id="outside"> tr> td id="t1">одинtd> tr> tr> td id="t2">дваtd> tr> table> 
    JavaScript Содержимое
    // Функция, изменяющая содержание t2 function modifyText(new_text)  var t2 = document.getElementById("t2"); t2.firstChild.nodeValue = new_text; > // Функция, добавляющая обработчик к таблице el = document.getElementById("outside"); el.addEventListener( "click", function ()  modifyText("четыре"); >, false, ); 

    Обратите внимание, что addEvenListener — это анонимная функция, которая инкапсулирует код, который, в свою очередь, может отправлять параметры функции modifyText(), которая отвечает за фактический ответ на событие.

    Результат

    Обработчик события со стрелочной функцией

    HTML
    table id="outside"> tr> td id="t1">onetd> tr> tr> td id="t2">twotd> tr> table> 
    JavaScript
    // Function to change the content of t2 function modifyText(new_text)  var t2 = document.getElementById("t2"); t2.firstChild.nodeValue = new_text; > // Add event listener to table with an arrow function var el = document.getElementById("outside"); el.addEventListener( "click", () =>  modifyText("four"); >, false, ); 
    Результат

    Обратите внимание: несмотря на то, что анонимные и стрелочные функции схожи, они имеют разные значения this .

    Примечания

    Зачем использовать addEventListener ?

    addEventListener — это способ зарегистрировать обработчик события, описанный в документации W3C DOM. Вот список преимуществ его использования:

    • Позволяет добавлять множество обработчиков для одного события. Это особенно полезно для DHTML библиотек или Mozilla extensions, которые должны работать в условиях использования сторонних библиотек/расширений.
    • Предоставляет точный контроль фазы срабатывания(вызова) обработчика (захват или всплытие).
    • Срабатывает на любом DOM-элементе, а не только на HTML-элементах.

    Добавление обработчика во время обработки события

    Если EventListener добавлен к EventTarget во время обработки события, он не будет вызван текущими действиями, но может быть вызван на более поздней стадии обработки события, при восходящей обработке.

    Несколько одинаковых обработчиков события

    Если зарегистрировано несколько одинаковых EventListener на одном EventTarget с одинаковыми параметрами, дублирующиеся обработчики игнорируются. Так как одинаковые обработчики игнорируются, не требуется удалять их вручную с помощью метода removeEventListener (en-US) .

    Значение this в обработчике

    Обычно желательно передавать элемент, на котором сработал обработчик события, например, при использовании обобщённых обработчиков для схожих элементов. При добавлении функции при помощи addEventListener() значение переменной this меняется — заметьте, что значение this передаётся в функцию от вызывающего объекта.

    В примере выше значение переменной this внутри modifyText() при вызове событием клика равно таблице ‘t’. Это противоположно поведению, которое возникает, если обработчик добавлен в HTML-разметке:

    table id="t" onclick="modifyText();"> . . . table> 

    Значение переменной this внутри modifyText() при вызове событием клика будет равно ссылке на глобальный (window) объект (или undefined при использовании strict mode)

    Примечание: В JavaScript 1.8.5 введён метод Function.prototype.bind() (en-US) , который позволяет указать значение, которое должно быть использовано для всех вызовов данной функции. Он позволяет вам легко обходить ситуации, в которых не ясно, чему будет равно this, в зависимости от того, в каком контексте будет вызвана ваша функция. заметьте, также, что вам будет необходимо иметь внешнюю ссылку на обработчик, чтобы вы могли удалить его позже.

    Пример с использованием bind и без него:

    var Something = function (element)  this.name = "Something Good"; this.onclick1 = function (event)  console.log(this.name); // undefined, так как this является элементом >; this.onclick2 = function (event)  console.log(this.name); // 'Something Good', так как в this передано значение объекта Something >; element.addEventListener("click", this.onclick1, false); element.addEventListener("click", this.onclick2.bind(this), false); // Trick >; 

    Проблема в примере выше заключается в том, что вы не можете удалить обработчик, вызванный с bind . Другое решение использует специальную функцию handleEvent , чтобы перехватывать любые события:

    var Something = function (element)  this.name = "Something Good"; this.handleEvent = function (event)  console.log(this.name); // 'Something Good', так как this является объектом Something switch (event.type)  case "click": // код обработчика. break; case "dblclick": // код обработчика. break; > >; // В этом случае обработчики хранятся в this, а не в this.handleEvent element.addEventListener("click", this, false); element.addEventListener("dblclick", this, false); // Вы можете напрямую удалять обработчики element.removeEventListener("click", this, false); element.removeEventListener("dblclick", this, false); >; 

    Наследство Internet Explorer и attachEvent

    В Internet Explorer младше 9 версии, вы можете использовать attachEvent вместо стандартного addEventListener . Для поддержки IE, пример выше может быть модифицирован следующим образом:

    if (el.addEventListener)  el.addEventListener("click", modifyText, false); > else if (el.attachEvent)  el.attachEvent("onclick", modifyText); > 

    У attachEvent есть недостаток: this будет ссылаться на объект window , а не на элемент, на котором он был вызван.

    Совместимость

    Вы можете обойти методы addEventListener , removeEventListener , Event.preventDefault и Event.stopPropagation не поддерживаемы в IE 8 используя следующий код в начале вашего скрипта. Этот код поддерживает использование handleEvent и события DOMContentLoaded .

    Примечание: useCapture не поддерживается, так как IE 8 не имеет альтернативного метода для этого. Также заметьте, что следующий код только добавляет поддержку IE 8. Также, он работает только при соблюдении стандартов: объявление DOCTYPE страницы обязательно.

    (function ()  if (!Event.prototype.preventDefault)  Event.prototype.preventDefault = function ()  this.returnValue = false; >; > if (!Event.prototype.stopPropagation)  Event.prototype.stopPropagation = function ()  this.cancelBubble = true; >; > if (!Element.prototype.addEventListener)  var eventListeners = []; var addEventListener = function ( type, listener /*, useCapture (will be ignored) */, )  var self = this; var wrapper = function (e)  e.target = e.srcElement; e.currentTarget = self; if (listener.handleEvent)  listener.handleEvent(e); > else  listener.call(self, e); > >; if (type == "DOMContentLoaded")  var wrapper2 = function (e)  if (document.readyState == "complete")  wrapper(e); > >; document.attachEvent("onreadystatechange", wrapper2); eventListeners.push( object: this, type: type, listener: listener, wrapper: wrapper2, >); if (document.readyState == "complete")  var e = new Event(); e.srcElement = window; wrapper2(e); > > else  this.attachEvent("on" + type, wrapper); eventListeners.push( object: this, type: type, listener: listener, wrapper: wrapper, >); > >; var removeEventListener = function ( type, listener /*, useCapture (will be ignored) */, )  var counter = 0; while (counter  eventListeners.length)  var eventListener = eventListeners[counter]; if ( eventListener.object == this && eventListener.type == type && eventListener.listener == listener )  if (type == "DOMContentLoaded")  this.detachEvent("onreadystatechange", eventListener.wrapper); > else  this.detachEvent("on" + type, eventListener.wrapper); > eventListeners.splice(counter, 1); break; > ++counter; > >; Element.prototype.addEventListener = addEventListener; Element.prototype.removeEventListener = removeEventListener; if (HTMLDocument)  HTMLDocument.prototype.addEventListener = addEventListener; HTMLDocument.prototype.removeEventListener = removeEventListener; > if (Window)  Window.prototype.addEventListener = addEventListener; Window.prototype.removeEventListener = removeEventListener; > > >)(); 

    Старый способ регистрации обработчиков событий

    addEventListener() был добавлен в спецификации DOM 2 Events. До этого обработчики добавлялись следующим образом:

    // Передача ссылки на функцию — не добавляйте '()' после него, это вызовет функцию! el.onclick = modifyText; // Использование функционального выражения element.onclick = function ()  // . логика функции . >; 

    Этот метод заменяет текущие обработчики события click , если они есть. Тоже самое для других событий и ассоциируемых с ними обработчиков, таких как blur ( onblur ), keypress ( onkeypress ), и так далее.

    Так как это по существу было частью DOM 0, этот метод имеет широкую поддержку и не требует специального кросс-браузерного кода; следовательно, это обычно используется, чтобы добавлять обработчики динамически, если не требуются расширенные возможности addEventListener() .

    Вопросы памяти

    var i; var els = document.getElementsByTagName("*"); // Случай 1 for (i = 0; i  els.length; i++)  els[i].addEventListener( "click", function (e)  /*некоторые действия*/ >, false, ); > // Случай 2 function processEvent(e)  /*некоторые действия*/ > for (i = 0; i  els.length; i++)  els[i].addEventListener("click", processEvent, false); > 

    В первом случае новая (анонимная) функция создаётся при каждом шаге цикла. Во втором случае одна заранее объявленная функция используется как обработчик события. Из этого следует меньшее потребление памяти. Более того, в первом случае, вследствие отсутствия ссылок на анонимные функции, невозможно вызвать element.removeEventListener, потому что нет ссылки на обработчик, в то время, как во втором случае возможно вызвать myElement.removeEventListener(«click», processEvent, false) .

    Улучшение производительности прокрутки с помощью passive: true

    Значение по умолчанию для параметра passive — false . Начиная с Chrome 56 (desktop, Chrome for Android, Android webview) значение по умолчанию для touchstart (en-US) и touchmove (en-US) равно true , а вызовы preventDefault() не разрешены. Чтобы отменить это поведение, необходимо установить параметр passive в false (см. пример ниже). Это изменение не позволяет обработчику блокировать показ страницы во время прокрутки пользователя. Демонстрация доступна на сайте разработчиков Google. Обратите внимание, что Edge вообще не поддерживает options , и добавление его без проверки поддержки помешает использовать аргумент useCapture .

    /* Не позволяем обработчику блокировать показ страницы */ var passiveSupported = false; try  window.addEventListener( "test", null, Object.defineProperty(>, "passive",  get: function ()  passiveSupported = true; >, >), ); > catch (err) > /* Добавляем обработчик событий */ var elem = document.getElementById("elem"); elem.addEventListener( "touchmove", function listener()  /* do something */ >, passiveSupported ?  passive: true > : false, ); 

    Установка passive не имеет значения для основного события scroll (en-US) , поскольку его нельзя отменить, поэтому его обработчик в любом случае не может блокировать показ страницы.

    Совместимость

    BCD tables only load in the browser

    Примечания по Gecko

    • До Firefox 6, браузер выбросит исключение, если параметр useCapture не был точно равен false . До Gecko 9.0, addEventListener() выбросит исключение, если параметр listener был равен null ; сейчас метод завершается без ошибки, но ничего не делает.

    Примечания по WebKit

    • Несмотря на то, что в WebKit параметр useCapture был объявлен необязательным только в июне 2011 года, это работало и до этого изменения. Новые изменения были добавлены в Safari 5.1 и Chrome 13.

    Спецификации

    Specification
    DOM Standard
    # ref-for-dom-eventtarget-addeventlistener③

    Совместимость с браузерами

    BCD tables only load in the browser

    Дополнительная информация

    • EventTarget.removeEventListener()
    • Creating and triggering custom events (en-US)
    • More details on the use of this in event handlers

    Found a content problem with this page?

    • Edit the page on GitHub.
    • Report the content issue.
    • View the source on GitHub.

    This page was last modified on 3 авг. 2023 г. by MDN contributors.

    Your blueprint for a better internet.

    MDN

    Support

    • Product help
    • Report an issue

    Our communities

    Developers

    • Web Technologies
    • Learn Web Development
    • MDN Plus
    • Hacks Blog
    • Website Privacy Notice
    • Cookies
    • Legal
    • Community Participation Guidelines

    Visit Mozilla Corporation’s not-for-profit parent, the Mozilla Foundation.
    Portions of this content are ©1998– 2023 by individual mozilla.org contributors. Content available under a Creative Commons license.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *