Свойство target — Передача объекта события обработчику события

Поговорим о таком понятии как объект события, о том, как его передать обработчику события. А также о свойстве target, которое указывает на элемент, сгенерировавший событие.
В конце страницы размещена иллюстрация, которая может помочь разобраться в материале.
На странице есть ТРИ полупрозрачных изображения.
Нужно сделать так, чтобы при щелчке на ЛЮБОМ из них левой кнопкой мыши изображение становилось полноценным.
Нужно написать ОДИН обработчик событий для всех изображений.
Объект события в JavaScript — Свойство target
/* 1. После полной загрузки страницы вызывается функция back_gr */
window.onload = back_gr;
/* 2. При щелчке на любом из 3-х изображений вызывается функция change, в которую передается Объект события images[i] — объект, представляющий изображение по которому щелкнули мышью */
function back_gr() <
var images = document.getElementsByTagName( ‘img’ );
for(i = 0; i < images.length; i++) <
images[i].onclick = change ;
>
>
/* 3. В функции change через свойство target мы обращаемся к Объекту события (к конкретному изображению) и меняем полупрозрачное изображение на полноценное */
function change( eventObj ) <
var images = eventObj . target ; /* сообщаем, какой элемент, т.е. какое изображение сгенерировало событие */
var img_id = images.id; /* получаем id изображения */
images.src = "img/peng_" + img_id + ".gif" /* используем id изображения для изменения атрибута src */
>
<body>
<img src= "img/peng_96_blur.gif" > ’96’ >
<img src= "img/peng_64_blur.gif" > ’64’ >
<img src= "img/peng_32_blur.gif" > ’32’ >
</body>
Разберем подробнее код из примера:
— делаем выборку всех изображений — тегов img ;
— при этом метод getElementsByTagName возвращает массив из тегов img , который заносится в переменную images ;
images[i].onclick = change;
То есть при щелчке левой кнопкой мыши на любом изображении вызывается одна и та же функция change() .
— при щелчке на изображении — оно становится источником события ;
— если быть точнее, то images[i] является объектом события «щелчка» и представляет то изображение, по которому произведен «щелчок»;
— далее Объект события «щелчка» передается обработчику события — функции change() :
images[i].onclick = change;
В обработчике события (в функции change) создается параметр eventObj — это условное название: оно удобно тем, что в переводе event — означает событие, а Obj ect — объект.
То есть присутствие параметра eventObj в функции change() означает, что в обработчик события передан Объект события .
Объект события содержит различную информацию о событии .
— сейчас нас интересует свойство target , которое содержит информацию о том, какой элемент сгенерировал событие (в нашем случае, какое изображение или тег img );
var images = eventObj.target;
Теперь через объект images мы можем обращаться к изображению, по которому щелкнули мышью. Мы можем получать или менять значения свойств объекта , то есть значения атрибутов тега img .
Какой параметр в обработчике события передает объект события которое обрабатывается
События сигнализируют системе о том, что произошло определенное действие. И если нам надо отследить эти действия, то как раз мы можем применять события.
Например, возьмем следующий класс, который описывает банковский счет:
В конструкторе устанавливаем начальную сумму, которая хранится в свойстве Sum. С помощью метода Put мы можем добавить средства на счет, а с помощью метода Take, наоборот, снять деньги со счета. Попробуем использовать класс в программе — создать счет, положить и снять с него деньги:
Все операции работают как и положено. Но что если мы хотим уведомлять пользователя о результатах его операций. Мы могли бы, например, для этого изменить метод Put следующим образом:
Казалось, теперь мы будем извещены об операции, увидев соответствующее сообщение на консоли. Но тут есть ряд замечаний. На момент определения класса мы можем точно не знать, какое действие мы хотим произвести в методе Put в ответ на добавление денег. Это может вывод на консоль, а может быть мы захотим уведомить пользователя по email или sms. Более того мы можем создать отдельную библиотеку классов, которая будет содержать этот класс, и добавлять ее в другие проекты. И уже из этих проектов решать, какое действие должно выполняться. Возможно, мы захотим использовать класс Account в графическом приложении и выводить при добавлении на счет в графическом сообщении, а не консоль. Или нашу библиотеку классов будет использовать другой разработчик, у которого свое мнение, что именно делать при добавлении на счет. И все эти вопросы мы можем решить, используя события.
Определение и вызов событий
События объявляются в классе с помощью ключевого слова event , после которого указывается тип делегата, который представляет событие:
В данном случае вначале определяется делегат AccountHandler, который принимает один параметр типа string. Затем с помощью ключевого слова event определяется событие с именем Notify, которое представляет делегат AccountHandler. Название для события может быть произвольным, но в любом случае оно должно представлять некоторый делегат.
Определив событие, мы можем его вызвать в программе как метод, используя имя события:
Поскольку событие Notify представляет делегат AccountHandler, который принимает один параметр типа string — строку, то при вызове события нам надо передать в него строку.
Однако при вызове событий мы можем столкнуться с тем, что событие равно null в случае, если для его не определен обработчик. Поэтому при вызове события лучше его всегда проверять на null. Например, так:
В этом случае поскольку событие представляет делегат, то мы можем его вызвать с помощью метода Invoke() , передав в него необходимые значения для параметров.
Объединим все вместе и создадим и вызовем событие:
Теперь с помощью события Notify мы уведомляем систему о том, что были добавлены средства и о том, что средства сняты со счета или на счете недостаточно средств.
Добавление обработчика события
С событием может быть связан один или несколько обработчиков. Обработчики событий — это именно то, что выполняется при вызове событий. Нередко в качестве обработчиков событий применяются методы. Каждый обработчик событий по списку параметров и возвращаемому типу должен соответствовать делегату, который представляет событие. Для добавления обработчика события применяется операция += :
Определим обработчики для события Notify, чтобы получить в программе нужные уведомления:
В данном случае в качестве обработчика используется метод DisplayMessage, который соответствует по списку параметров и возвращаемому типу делегату AccountHandler. В итоге при вызове события Notify?.Invoke() будет вызываться метод DisplayMessage, которому для параметра message будет передаваться строка, которая передается в Notify?.Invoke() . В DisplayMessage просто выводим полученное от события сообщение, но можно было бы определить любую логику.
Если бы в данном случае обработчик не был бы установлен, то при вызове события Notify?.Invoke() ничего не происходило, так как событие Notify было бы равно null.
Консольный вывод программы:
Теперь мы можем выделить класс Account в отдельную библиотеку классов и добавлять в любой проект.
Добавление и удаление обработчиков
Для одного события можно установить несколько обработчиков и потом в любой момент времени их удалить. Для удаления обработчиков применяется операция -= . Например:
В качестве обработчиков могут использоваться не только обычные методы, но также делегаты, анонимные методы и лямбда-выражения. Использование делегатов и методов:
В данном случае разницы между двумя обработчиками никакой не будет.
Установка в качестве обработчика анонимного метода:
Установка в качестве обработчика лямбда-выражения:
Управление обработчиками
С помощью специальных акссесоров add/remove мы можем управлять добавлением и удалением обработчиков. Как правило, подобная функциональность редко требуется, но тем не менее мы ее можем использовать. Например:
Теперь опредление события разбивается на две части. Вначале просто определяется переменная делегата, через которую мы можем вызывать связанные обработчики:
Во второй части определяем акссесоры add и remove. Аксессор add вызывается при добавлении обработчика, то есть при операции +=. Добавляемый обработчик доступен через ключевое слово value . Здесь мы можем получить информацию об обработчике (например, имя метода через value.Method.Name) и определить некоторую логику. В данном случае для простоты просто выводится сообщение на консоль:
Блок remove вызывается при удалении обработчика. Аналогично здесь можно задать некоторую дополнительную логику:
Внутри класса событие вызывается также через переменную notify. Но для добавления и удаления обработчиков в программе используется как раз Notify:
Консольный вывод программы:
Передача данных события
Нередко при возникновении события обработчику события требуется передать некоторую информацию о событии. Например, добавим и в нашу программу новый класс AccountEventArgs со следующим кодом:
Данный класс имеет два свойства: Message — для хранения выводимого сообщения и Sum — для хранения суммы, на которую изменился счет.
Теперь применим класс AccoutEventArgs, изменив класс Account следующим образом:
По сравнению с предыдущей версией класса Account здесь изменилось только количество параметров у делегата и соответственно количество параметров при вызове события. Теперь делегат AccountHandler в качестве первого параметра принимает объект, который вызвал событие, то есть текущий объект Account. А в качестве второго параметра принимает объект AccountEventArgs, который хранит информацию о событии, получаемую через конструктор.
Теперь изменим основную программу:
По сравнению с предыдущим вариантом здесь мы только изменяем количество параметров и их использования в обработчике DisplayMessage. Благодаря первому параметру в методе можно получить информацию об отправителе события — счете, с которым производится операция. А через второй параметр можно получить инфомацию о состоянии операции.
Какой параметр в обработчике события передает объект события которое обрабатывается
Какой параметр в обработчике события передает объект события которое обрабатывается
Для взаимодействия с пользователем в Windows Forms используется механизм событий. События в Windows Forms представляют стандартные события на C#, только применяемые к визуальным компонентам и подчиняются тем же правилам, что события в C#. Но создание обработчиков событий в Windows Forms все же имеет некоторые особенности.
Прежде всего в WinForms есть некоторый стандартный набор событий, который по большей части имеется у всех визуальных компонентов. Отдельные элементы добавляют свои события, но принципы работы с ними будут похожие. Чтобы посмотреть все события элемента, нам надо выбрать этот элемент в поле графического дизайнера и перейти к вкладке событий на панели форм. Например, события формы:

Чтобы добавить обработчик, можно просто два раза нажать по пустому полю рядом с названием события, и после этого Visual Studio автоматически сгенерирует обработчик события. Например, нажмем для создания обработчика для события Load :

И в этом поле отобразится название метода обработчика события Load. По умолчанию он называется Form1_Load .
Если мы перейдем в файл кода формы Form1.cs, то увидим автосгенерированный метод Form1_Load:
И при каждой загрузке формы будет срабатывать код в обработчике Form1_Load.
Как правило, большинство обработчиков различных визуальных компонентов имеют два параметра: sender — объект, инициировавший событие, и аргумент, хранящий информацию о событии (в данном случае EventArgs e ).
Но это только обработчик. Добавление же обработчика, созданного таким образом, производится в файле Form1.Designer.cs:
Для добавления обработчика используется стандартный синтаксис C#: this.Load += new System.EventHandler(this.Form1_Load)
Поэтому если мы захотим удалить созданный подобным образом обработчик, то нам надо не только удалить метод из кода формы в Form1.cs, но и удалить добавление обработчика в этом файле.
Однако мы можем добавлять обработчики событий и програмно, например, в конструкторе формы:
Обработка событий в .NET с помощью C#
В этой статье я расскажу о модели обработки событий в .NET с помощью C#. Обсуждение начнется с введения в концепцию делегатов, а затем расширится концепциями событий и их обработкой в .NET. В конце концов, мы применим механизм к событиям графического пользовательского интерфейса (Graphical User Interface — GUI), используя формы Windows. Дискуссия сопровождается законченными примерами.
Введение
Обработка событий хорошо известна тем разработчикам, которые программировали графический пользовательский интерфейс. Когда пользователь взаимодействует с ним (например, нажав кнопку), один или более методов, ожидающих этого отклика, запускаются. Событие может быть сгенерировано и без взаимодействия с пользователем. Обработчики событий это методы в объекте, привязанные к событию, возникающему в приложении. Чтобы разобраться в механизме обработки событий необходимо понимать принципы делегатов.
Делегаты в C#
Делегаты в C# позволяют применять методы одного класса к объектам другого класса, который может эти методы вызвать. Вы можете применить метод m класса A, определенного в делегате, к классу B, который будет способен вызвать метод m класса A. Вы можете вызвать как статические методы, так и нестатические. Эта концепция хорошо известна разработчикам C++, которые использовали указатель на функцию в качестве параметра, передаваемого другой функции. Концепция делегатов была введена в Visual J++, а затем перенесена в C#. Делегаты C# являются в .NET Framework реализацией в качестве производного класса от System.Delegate. Использование делегатов можно описать четырьмя шагами.
- Определение объекта делегата с сигнатурой, точно соответствующей сигнатуре метода, который пытаемся связать.
- Определение метода с сигнатурой делегата, определенного на первом шаге
- Создание объекта делегата и связывание их с методами
- Вызов связанного метода с помощью объекта делегата
Следующий C# код показывает вышеупомянутые шаги в реализации одного делегата и четырех классов.
Обработчики событий в C#
Обработчик события это делегат со специальной сигнатурой.
Первый параметр (sender) в вышеупомянутом определении определяет объект, который издает событие. Второй параметр (e) содержит данные, которые должны быть использованы обработчиком события. Класс MyEventArgs должен быть производным от класса EventArgs. EventArgs является базовым классом для более специализированных классов, таких как MouseEventArgs, ListChangedEventArgs и т.д. Для GUI события вы можете применять объекты этих специализированных классов без создания своего собственного. Однако, для остальных событий вы должны свой класс и держать в нем данные, которые вы хотите передать делегату. Пример создания собственного класса.
В случае обработчика событий делегат, на который объект ссылается, помечается ключевым словом event.
Сейчас мы на примере двух классов рассмотрим, как данный механизм работает. На втором шаге нашей дискуссии делегат требовал определения метода с такой же сигнатурой. В нашем примере класс A определяет обработчики событий (методы с сигнатурой аналогичной делегатам). Далее свяжем их с соответствующими делегатами. Метод класса A примет с помощью делегата объект класса B. Затем при возникновении события в классе B будет вызван обработчик события, т.е. метод класса A.
Обработка событий GUI в C#
Для обработки событий Winfows Form (.NET Framework поддерживает GUI приложения) применяется модель, описанная ранее. Рассмотрим на примере простого приложения. Определим класс MyForm, унаследованный от класса System.Windows.Forms.Form. Если вы проанализируете код и комментарии, то вы заметите, что мы не определяем делегат, используя ключевое слово event, т.к. события (нажатие мышью и т.д.) для GUI элементов (форма, кнопка и т.д.) уже доступны вам с помощью делегата System.EvantHandler. Однако все еще необходимо создавать объект делегата (System.EvantHandler) и встраивать его в метод, который должен реагировать отклик на событие.
Заключение
Другие популярные объектно-ориентированные языки подобные Java и Smalltalk не содержат в своем арсенале концепции делегатов. Это новшество для C#, наследуемое от C++ и J++. Я надеюсь, что вышеупомянутая дискуссия прояснила концепцию тем программистам, для которых C# является первым объектно-ориентированным языком. Если вы используете Visual Studio IDE для своих C# GUI разработок, код связывания делегатов с методами будет генерироваться автоматически управлением GUI (подобно нажатию кнопки мыши). Анализировать эту работу это лучший вариант узнать, что скрывается на самом деле под колпаком.
Выразительный JavaScript: Обработка событий
Некоторые программы работают с вводом пользователя, мышью и клавиатурой. Время возникновения такого ввода и последовательность данных нельзя предсказать заранее. Это требует иного подхода к контролю над порядком выполнения программы, чем уже привычный нам.
Обработчики событий
Представьте интерфейс, в котором единственным способом узнать, нажали ли на кнопку клавиатуры, было бы считывание текущего состояния кнопки. Чтобы реагировать на нажатия, вам пришлось бы постоянно считывать состояния кнопок, чтобы вы могли поймать это состояние, пока кнопка не отжалась. Было бы опасно проводить другие подсчёты, отнимающие процессорное время, так как можно было бы пропустить момент нажатия.
Таким образом ввод обрабатывался на примитивных устройствах. Шагом вперёд было бы, если железо или операционка замечали бы нажатие кнопки и передавали бы его в очередь. Затем программа периодически могла бы проверять очередь на новые события и реагировать на то, что находится в очереди.
Разумеется, она должна помнить о проверке, и делать это достаточно часто, потому что наличие длительного промежутка времени между нажатием кнопки и тем, когда программа замечает и реагирует на это, ведёт к восприятию этой программы как медленно работающей. Такой подход называется опросом. Большинство программистов по возможности избегают его. Такой подход используется достаточно редко.
Вариант получше – некая промежуточная система, которая позволяет коду реагировать на события в момент их возникновения. Браузеры позволяют это делать путём регистрации функций как обработчиков заданных событий.
Функция addEventListener регистрирует свой второй аргумент как функцию, которая вызывается, когда описанное в первом аргументе событие случается.
События и узлы DOM
Каждый обработчик событий браузера зарегистрирован в контексте. Когда вы вызываете addEventListener, вы вызываете её как метод целого окна, потому что в браузере глобальная область видимости – это объект window. У каждого элемента DOM есть свой метод addEventListener, позволяющий слушать события от этого элемента.
Пример назначает обработчик на DOM-узел кнопки. Нажатия на кнопку запускают обработчик, а нажатия на другие части документа – не запускают.
Присвоение узлу атрибута onclick работает похоже. Но у узла есть только один атрибут onclick, значит таким способом вы можете зарегистрировать только один обработчик. Метод addEventListener позволяет добавлять любое количество обработчиков, так что вы не замените случайно уже назначенный ранее обработчик.
Метод removeEventListener, вызванный с такими же аргументами, как addEventListener, удаляет обработчик.
Чтобы это провернуть, мы даём функции имя (в данном случае, once), чтобы её можно было передать и в addEventListener, и в removeEventListener.
Объекты событий
В примерах мы проигнорировали тот факт, что функциям-обработчикам передаётся аргумент – объект события. В нём хранится дополнительная информация о событии. К примеру, если надо узнать, какая кнопка мыши была нажата, мы можем обратиться к свойству which этого объекта.
Хранящаяся в объекте информация – разная для каждого типа событий. Мы обсудим эти типы позже. Свойство объекта type всегда содержит строку, описывающую событие (например, «click» или «mousedown»).
Распространение (propagation)
События, зарегистрированные на узлах, имеющих дочерние узлы, получат и некоторые события, случившиеся с их детьми. Если кликнуть на кнопку внутри параграфа, обработчики событий параграфа получат событие click.
Если и у параграфа и у кнопки есть обработчики, то первым запустится более конкретный – то есть, обработчик кнопки. Событие как бы распространяется наружу, от узла, где оно случилось, до его родительского и далее до корня документа. После отработки всех обработчиков всех промежуточных узлов, очередь среагировать на событие доходит и до самого окна.
В любой момент обработчик может вызвать метод stopPropagation объекта события, чтобы «высшие» узлы не получили его. Это может быть полезным, когда у вас есть кнопка внутри другого кликабельного элемента, и вы не хотите, чтобы клики по кнопке активировали поведение внешнего элемента.
Следующий пример регистрирует обработчики «mousedown» как на кнопке, так и на окружающем параграфе. При щелчке правой кнопкой обработчик кнопки вызывает stopPropagation, который предотвращает запуск обработчика параграфа. При клике другой кнопкой запускаются оба обработчика.
У большинства объектов событий есть свойство target, ссылающееся на узел, который запустил обработку. Его можно использовать для проверки того, что вы не обрабатываете что-то, пришедшее с ненужного вам узла.
Также возможно использовать свойство target, чтобы распространить обработку конкретного типа события. К примеру, если у вас есть узел, содержащий длинный список кнопок, было бы удобнее зарегистрировать один обработчик событий для узла, и в нём выяснять, нажали ли на кнопку – вместо того, чтобы регистрировать обработчики каждой кнопки по отдельности.
Действия по умолчанию
У многих событий есть действия по умолчанию. При клике на ссылку вы перейдёте по ней. При нажатии на стрелку вниз браузер прокрутит страницу вниз. По правому клику мыши вы увидите контекстное меню. И так далее.
Для большинства типов событий обработчики событий вызываются до того, как сработает действие по умолчанию. Если обработчик не хочет, чтобы это действие происходило (часто потому, что он уже обработал его), он может вызвать метод preventDefault объекта события.
Это можно использовать для создания своих горячих клавиш или контекстного меню. Также это можно использовать для слома привычного пользователю интерфейса. К примеру, вот ссылка, по которой нельзя пройти.
Не делайте так – если у вас нет очень серьёзной причины! Пользователям вашей страницы будет очень неудобно, когда они столкнутся с неожиданными результатами своих действий. В зависимости от браузера, некоторые события перехватить нельзя. В Chrome нельзя обрабатывать горячие клавиши закрытия текущей закладки (Ctrl-W or Command-W).
События от кнопок клавиатуры
При нажатии кнопки на клавиатуре браузер запускает событие «keydown». Когда она отпускается, происходит событие «keyup».
Несмотря на название, «keydown» происходит не только тогда, когда на кнопку нажимают. Если нажать и удерживать кнопку, событие будет происходить каждый раз по приходу повторного сигнала от клавиши (key repeat). Если вам, к примеру, надо увеличивать ускорение игрового персонажа, когда нажата кнопка со стрелкой, и уменьшать его, когда она отпущена – надо быть осторожным, чтобы не увеличивать ускорение каждый раз при повторе сигнала от кнопки, иначе скорость возрастёт очень сильно.
В примере упомянуто свойство keyCode объекта события. Так вы можете узнать, какая именно кнопка нажата или отпущена. К сожалению, не всегда очевидно, как преобразовать числовые коды в нужную кнопку.
Для цифр и букв код будет кодом символа Unicode, связанного с прописным символом, изображённым на кнопке. Метод строки charCodeAt даёт нам этот код.
У других кнопок коды менее предсказуемы. Лучший способ их выяснить – экспериментальный. Зарегистрировать обработчик, который записывает коды клавиш, и нажать нужную кнопку.
Кнопки-модификаторы типа Shift, Ctrl, Alt, и Meta (Command на Mac) создают события, как и нормальные кнопки. Но при разборе комбинаций клавиш можно выяснить, были ли нажаты модификаторы, через свойства shiftKey, ctrlKey, altKey, и metaKey событий клавиатуры и мыши.
События «keydown» и «keyup» дают информацию о физическом нажатии кнопок. А если вам нужно узнать, какой текст вводит пользователь? Создавать его из нажатий кнопок – неудобно. Для этого существует событие «keypress», происходящее сразу после «keydown» (и повторяющееся вместе с «keydown», если клавишу продолжают удерживать), но только для тех кнопок, которые выдают символы. Свойство объекта события charCode содержит код, который можно интерпретировать как код Unicode. Мы можем использовать функцию String.fromCharCode для превращения кода в строку из одного символа.
Источником события нажатия клавиши узел становится в зависимости от того, где находился фокус ввода во время нажатия. Обычные узлы не могут получить фокус ввода (если только вы не задали им атрибут tabindex), а такие, как ссылки, кнопки и поля форм – могут. Мы вернёся к полям ввода в главе 18. Когда ни у чего нет фокуса, в качестве целевого узла событий работает «document.body».
Щелчки мышью
Нажатие кнопки мыши тоже запускает несколько событий. События «mousedown» и «mouseup» похожи на «keydown» и «keyup», и запускаются, когда кнопка нажата и когда отпущена. События происходят у тех узлов DOM, над которыми находился курсор мыши.
После события «mouseup» на узле, на который пришлись и нажатие, и отпускание кнопки, запускается событие “click”. Например, если я нажал кнопку над одним параграфом, потом передвинул мышь на другой параграф и отпустил кнопку, событие “click” случится у элемента, который содержал в себе оба эти параграфа.
Если два щелчка происходят достаточно быстро друг за другом, запускается событие «dblclick» (double-click), сразу после второго запуска “click”.
Для получения точных координат места, где произошло событие мыши, обратитесь к свойствам pageX и pageY – они содержат координаты в пикселях относительно верхнего левого угла документа.
В примере создана примитивная программа для рисования. Каждый раз по клику на документе он добавляет точку под вашим курсором. В главе 19 будет представлена менее примитивная программа для рисования.
Свойства clientX и clientY похожи на pageX и pageY, но дают координаты относительно части документа, которая видна сейчас (если документ был прокручен). Это удобно при сравнении координат мыши с координатами, которые возвращает getBoundingClientRect – его возврат тоже связан с относительными координатами видимой части документа.
Движение мыши
Каждый раз при сдвиге курсора мыши запускается событие «mousemove». Его можно использовать для отслеживания позиции мыши. Обычно это нужно при создании некоей функциональности, связанной с перетаскиванием объектов мышью.
К примеру, следующая программа отображает полоску и устанавливает обработку событий так, что движение влево и вправо уменьшает или увеличивает её ширину.
Обратите внимание – обработчик «mousemove» зарегистрирован у всего окна. Даже если мышь уходит за пределы полоски, нам надо обновлять её размер и прекращать это, когда кнопку отпускают.
Когда курсор попадает на узел и уходит с него, происходят события «mouseover» или «mouseout». Их можно использовать, кроме прочего, для создания эффектов проведения мыши, показывая или меняя стиль чего-либо, когда курсор находится над этим элементом.
К сожалению, создание такого эффекта не ограничивается запуском его при событии «mouseover» и завершением при событии «mouseout». При движении мыши от узла к его дочерним узлам на родительском узле происходит событие «mouseout», хотя мышь, вообще говоря, его и не покидала. Что ещё хуже, эти события распространяются как и все другие, поэтому вы всё равно получаете «mouseout» при уходе курсора с одного их дочерних узлов того узла, где вы зарегистрировали обработчик.
Для обхода проблемы можно использовать свойство relatedTarget объекта событий. Он сообщает, на каком узле была до этого мышь при возникновении события «mouseover», и на какой элемент она переходит при событии «mouseout». Нам надо менять эффект, только когда relatedTarget находится вне нашего целевого узла. Только в этом случае событие на самом деле представляет собой переход на наш узел (или уход с узла).
Функция isInside перебирает всех предков узла, пока не доходит до верха документа (и тогда узел равен null), или же не находит заданного ей родителя.
Должен добавить, что такой эффект достижим гораздо проще через псевдоселектор CSS под названием :hover, как показано ниже. Но когда при наведении вам надо делать что-то более сложное, чем изменение стиля узла, придётся использовать трюк с событиями «mouseover» и «mouseout».
События прокрутки
Когда элемент прокручивается, запускается событие «scroll». Это используется во многих случаях, например чтобы узнать, на что сейчас пользователь смотрит (чтобы останавливать анимацию, не попавшую на экран, или отправлять секретные шпионские донесения в ваш злодейский штаб), или визуально демонстрировать прогресс (подсвечивая часть содержания или показывая номер страницы).
В примере в правом верхнем углу документа создаётся индикатор процесса, который заполняется по мере прокрутки элемента вниз.
Позиция элемента fixed означает почти то же, что absolute, но ещё и предотвращает прокручивание элемента вместе с остальным документом. Смысл в том, чтобы оставить наш индикатор в углу. Внутри него находится другой элемент, который изменяет размер, отражая текущий прогресс. Мы используем проценты вместо px для задания ширины, чтобы размер элемента изменялся относительно размера всего индикатора.
Глобальная переменная innerHeight даёт высоту окна, которую надо вычесть из полной высоты прокручиваемого элемента – при достижении конца элемента прокрутка заканчивается. (Также в дополнение к innerHeight есть переменная innerWidth). Поделив текущую позицию прокрутки pageYOffset на максимальную позицию прокрутки, и умножив на 100, мы получили процент для индикатора.
Вызов preventDefault не предотвращает прокрутку. Обработчик события вызывается уже после того, как прокрутка случилась.
События, связанные с фокусом
При получении элементом фокуса браузер запускает событие “focus”. Когда он теряет фокус, запускается событие “blur”.
В отличие от предыдущих событий, эти два не распространяются. Обработчик родительского узла не уведомляется о получении или утрате фокуса дочерним элементом.
Следующий пример демонстрирует текст подсказки для того текстового поля, у которого в данный момент фокус.
Объект window получает события focus и blur, когда пользователь выделяет или убирает фокус с закладки браузера или окна браузера, в котором показан документ.
Событие загрузки
Когда заканчивается загрузка страницы, на объектах window и body запускается событие “load”. Это часто используется для планирования инициализирующих действий, которым необходим полностью построенный документ. Вспомните, что содержимое тегов <script> запускается сразу, как только тег встречается. Иногда это слишком рано – например, когда скрипту нужно что-то сделать с теми частями документа, которые находятся после тега <script>.
У элементов типа картинок или тегов скрипта, которые загружают внешний файл, тоже есть событие “load”, которое показывает, что файл загружен. Как и события фокуса, события загрузки не распространяются.
Когда страница закрывается или с неё уходят (например, по ссылке), запускается событие «beforeunload». Основная цель – защитить пользователя от случайной потери данных при закрытии документа. Предотвращение закрытия страницы не производится, как вы могли подумать, при помощи preventDefault. Вместо этого используется возврат строки из обработчика. Строка будет использована в диалоге, который спрашивает пользователя, хочет ли он остаться на странице или покинуть её. Этот механизм гарантирует, что пользователь может покинуть страницу, даже если на ней работает зловредный скрипт, который бы хотел не отпускать пользователя, а вместо этого показывал бы ему мошенническую рекламу по снижению веса.
График выполнения скрипта
Несколько вещей могут привести к старту скрипта. Чтение тега <script> — одна из них. Запуск события – ещё одна. В главе 13 обсуждается функция requestAnimationFrame, которая планирует запуск функции перед следующей перерисовкой страницы. Это ещё один способ запустить скрипт.
Важно понять, что хотя события и запускаются в любой момент, два разных скрипта одновременно работать не могут. Если скрипт работает, обработчики событий и запланированные другим способом куски кода будут ждать своей очереди. Поэтому документ подвисает, когда скрипт работает слишком долго. Браузер не обрабатывает щелчки и другие события внутри документа потому, что он не может запустить обработчики событий, пока работает текущий скрипт.
В некоторых программных окружениях можно запускать несколько потоков одновременно. Можно сделать программу быстрее, если выполнять несколько вещей одновременно. Но когда несколько действующих лиц трогают одни и те же части системы в одно и то же время, продумывать программу становится на порядок сложнее.
То, что программы JavaScript делают по одной вещи за раз, облегчает нашу жизнь. Если вам очень надо сделать в фоне что-то тяжёлое, не подвешивая при этом страницу, браузеры предоставляют штуку под названием «сетевые рабочие» (web worker) – изолированное окружение JavaScript, работающее вместе с главной программой над документом, которое может общаться с ней только посредством сообщений.
Предположим, у нас есть следующий код в файле code/squareworker.js:
Представьте, что возведение в квадрат – очень тяжёлое, долго работающее вычисление, которое нам надо запустить фоновым потоком. Такой код порождает «рабочего», отправляет ему несколько сообщений, и выводит результаты.
Функция postMessage отправляет сообщение, которое запускает событие “message” у принимающей стороны. Скрипт, создавший рабочего, отправляет и получает сообщения через объект Worker, тогда как рабочий общается со скриптом, создавшим его, отправляя и получая сообщения через его собственное глобальное окружение – которое является отдельным окружением, не связанным с оригинальным скриптом.
Установка таймеров
Функция setTimeout схожа с requestAnimationFrame. Она планирует запуск другой функции в будущем. Но вместо вызова функции при следующей перерисовке страницы, она ждёт заданное в миллисекундах время. Эта страница через две секунды превращается из синей в жёлтую:
Иногда вам надо отменить запланированную функцию. Это можно сделать, сохранив значение, возвращаемое setTimeout, и затем вызвав с ним clearTimeout.
Функция cancelAnimationFrame работает так же, как clearTimeout – вызов её со значением, возвращённым requestAnimationFrame, отменит этот кадр (если он уже не был вызван).
Похожий набор функций, setInterval и clearInterval используется для установки таймеров, которые будут повторяться каждые X миллисекунд.
Устранение помех (debouncing)
У некоторых событий есть возможность выполняться быстро и много раз подряд (например, «mousemove» и «scroll»). При обработке таких событий надо быть осторожным и не делать ничего «тяжёлого», или ваш обработчик займёт столько времени на выполнение, что взаимодействие с документом будет медленным и прерывистым.
Если в таком обработчике надо сделать что-то нетривиальное, можно использовать setTimeout, чтобы гарантировать, что вы делаете это не слишком часто. Это обычно называют «устранением помех» в событии. К этому существует несколько слегка различающихся подходов.
В первом примере надо сделать что-то, когда пользователь печатает, но не надо делать это сразу после запуска каждого события нажатия на клавиши. Когда они быстро печатают, нам надо подождать, когда возникнет пауза. Вместо немедленного выполнения действия в обработчике, мы устанавливаем таймаут. Также мы очищаем предыдущий таймаут, если он был, так что если события близко одно от другого (ближе, чем задержка таймера), предыдущее событие будет отменено.
Если задать undefined для clearTimeout, или вызвать его с таймаутом, который уже произошёл, то ничего не произойдёт. Таким образом, не надо осторожничать при его вызове, и мы просто поступаем так для каждого события.
Можно использовать немного другой подход, если нам надо разделить ответы минимальными промежутками времени, но при этом запускать их в то время, когда происходят события, а не после. К примеру, надо реагировать на события «mousemove», показывая текущие координаты мыши, но только каждые 250 миллисекунд.
Обработчики событий позволяют обнаруживать и реагировать на события, над которыми мы не властны. Для их регистрации используется метод addEventListener.
У событий есть определяющий их тип («keydown», «focus», и так далее). Большинство событий вызываются конкретными узлами DOM, и затем распространяются на их предков, позволяя связанными с ними обработчикам обрабатывать их.
При вызове обработчика ему передаётся объект события с дополнительной информацией о событии. У объекта также есть методы, позволяющие остановить дальнейшее распространение (stopPropagation) и предотвратить обработку события браузером по умолчанию (preventDefault).
Нажатия на клавиши запускают события «keydown», «keypress» и «keyup». Нажатия на кнопки мыши запускают события «mousedown», «mouseup» и «click». Движения мыши запускают события «mousemove», и возможно «mouseenter» и «mouseout».
Прокрутку можно обнаружить через событие “scroll”, а изменения фокуса через события «focus» и «blur». Когда заканчивается загрузка документа, у объекта window запускается событие “load”.
В одно и то же время может работать один участок программы. Поэтому обработчики событий и другие запланированные скрипты будут ждать окончания работы текущих.
Упражнения
Цензура клавиатуры
В промежутке с 1928 по 2013 год турецкие законы запрещали использование букв Q, W и X в официальных документах. Это являлось частью общей инициативы подавления курдской культуры – эти буквы используются в языке курдов, но не у турков.
В качестве упражнения на тему странного использования технологий, я прошу вас запрограммировать поле для ввода текста так, чтобы эти буквы нельзя было туда вписать. Насчет копирования и вставки и других подобных возможных обходов правила не беспокойтесь.
След мыши
В ранние дни JavaScript, когда было время кричащих домашних страниц с обилием анимированных картинок, люди использовали язык очень вдохновляющими способами. Одним из них был «след мыши» — серия картинок, которые следовали за курсором при его движении по странице.
Я хочу, что бы вы в упражнении сделали такой след. Используйте <div> с абсолютным позиционированием, фиксированным размером и цветом фона. Создайте кучку элементов и при движении мыши показывайте их следом за курсором.
К этому можно подойти многими способами. Можно сделать очень простое или очень сложное решение, как угодно. Простое – хранить фиксированное количество элементов и проходить по ним в цикле, двигая каждый следующий на текущее место курсора, каждый раз когда случается событие «mousemove».
Закладки
Интерфейс закладок встречается часто. Он позволяет вам выбирать панель интерфейса, выбирая одну из нескольких торчащих закладок над элементом.
В упражнении вам нужно сделать простой интерфейс закладок. Напишите функцию asTabs, которая принимает узел DOM, и создаёт закладочный интерфейс, показывая дочерние элементы этого узла. Ей нужно вставлять список элементов <button> вверху узла, по одному на каждый дочерний элемент, содержащих текст, полученный из атрибута data-tabname. Все, кроме одного из дочерних элементов, должны быть спрятаны (при помощи значения none свойства стиля display), а текущий видимый узел можно выбирать нажатием кнопки.
Когда оно заработает, расширьте функционал, чтобы у текущей активной кнопки был свой стиль.
События и делегаты
В Заметке о консольных и оконных (Windows Forms) приложениях мы отметили существенную разницу между ними. Консольное приложение реализует концепцию императивного (процедурного) программирования, а управление Windows-приложением основано на понятии события (event). События могут создаваться как пользователем, так и возникать в процессе выполнения приложения. Начнем с простых вещей.
Создадим оконное приложение и запустим его на выполнение. С пустой формой мы можем выполнить только несколько стандартных действий: изменить размер, свернуть, свернуть в окно/развернуть и закрыть приложение.
Для изменения размеров формы подведем указатель мыши (1 событие) к любой ее границе (указатель изменит свою форму), перетянем ее в нужном направлении (2 событие) и отпустим кнопку (3 событие). Последние три действия с формой выполняются после клика мышью (событие 4) на кнопках формы.
Ясно, что такое приложение нам не слишком интересно, тем не менее, очевидна связь между событиями и действиями.
Перенесем с Панели элементов на форму объект «Кнопка» (по умолчанию – button1 класса Button). На вкладке «Конструктор» кнопка видна, на вкладке «Код» о ней нет никакой информации. Однако раскрыв файл Form1.Designer.cs, мы увидим в описании класса Form1 поле:
private System.Windows.Forms.Button button1;
которое задает этот объект, а в методе private void InitializeComponent() обнаружим описание его свойств (имя, местоположение, размер, надпись и т.п.).
Запустим программу снова на выполнение. Нажатие на кнопку (событие) не влечет за собой никаких действий (кроме того, что между нажатием и отпусканием кнопки она подсвечивается).
Смотрим книгу «для чайников». В ней написано: чтобы связать это событие с каким-либо действием необходимо всего лишь выполнить двойной клик на кнопке, в окне кода появится заготовка для метода – обработчика события Click:
private void button1_Click(object sender, EventArgs e)
Увеличим ширину кнопки примерно в три раза. Вставим в тело метода между фигурными скобками оператор:
button1.Text = DateTime.Now.ToString();
Теперь при нажатии кнопки непосредственно на ней мы можем прочитать текущие дату и время нажатия на кнопку.
«Выдающийся» результат! Есть событие, есть реакция на него (обработка события). Как Вам такая автоматизация программирования!
Заметим, что в панели Свойства для объекта button1 на закладке События (щелчок на «желтой молнии») напротив события Click появился метод button1_Click. В окне кода добавили всего один метод с одним оператором в его теле. Что же еще изменилось? Посмотрим содержимое файла Form1.Designer.cs. В нем добавилась загадочная строка:
this.button1.Click += new System.EventHandler(this.button1_Click);
Расшифруем ее. Ключевое слово this – это ссылка на текущий объект Form1 (забавно, что имя объекта совпадает с именем класса). Объект button1 размещен на форме Form1. А Click – очевидно это событие, клик на кнопке. EventHandler – делегат (delegate), представляет метод, который будет обрабатывать событие, не имеющее данных (объявлен в библиотеке System). Тип события обязательно должен совпадать с типом делегата. В скобках указывается имя этого метода button1_Click.
Переведем смысл оператора на русский язык:
Объект.Событие += new Делегат(Метод_обработки);
Символ + определяет подписку обработчика события.
Очевидный вывод: Подписка на событие с использованием делегата приводит к вызову метода при возникновении события.
Возможен ли разрыв связи между событием и методом его обработки? И нет ли у вас ощущения статичности таких связей? Можно ли то же самое достичь программным путем?
Реализуем второй вариант действий:
1) поместим кнопку button1 на форме Form1;
2) в конструктор формы добавим один оператор, тогда:
public Form1()
3) в описание класса добавим метод:
private void button1_Click(object sender, EventArgs e)
4) запустим программу на выполнение, сравним результаты;
5) появился ли оператор подключения в файле FormDesigner.cs ?
Заметим, что этот файл Form1.Designer.cs является текстовым описанием формы и размещенных на ней элементов после запуска программы, что позволяет отобразить ее в режиме конструктора.
Далее многое можно изменять программным путем.
Итак, событие – это сообщение другим объектам программы, что произошло какое-то действие. Действие может быть инициировано пользователем (нажатие клавиши) или же в результате выполнения какого-то фрагмента программы (по условию).
Объект, который вызывает событие, называется отправителем (sender) сообщения, а объект, который сообщение получает – получателем. Роль «почтальона» выполняет делегат. Получатель сообщения имеет метод, который автоматически выполняется в ответ на исходное событие. В нашем примере отправителем и получателем сообщения является объект button1 («makes himself»).
Платформа .NET Framework поддерживает простое программирование событий, из-за чего начинающие программисты часто не вникают в работу событий.
Событием в языке C# называется сущность, предоставляющая две возможности: сообщать об изменениях, а для его пользователей — реагировать на них. В объявлениях классов визуальных компонентов мы найдем большое количество событий, которые могут быть вам полезны. Подсчитайте, сколько событий связано с формой? У меня получилось – 76. А для кнопки – 58, не мало? Если же вам необходимо создать собственное событие, то вы можете его просто объявить:
public event EventHandler myEvent;
Рассмотрим, из чего состоит объявление. Сначала идут модификаторы события, затем ключевое слово event, после него — тип события, который обязательно должен быть типом-делегатом, и идентификатор события, то есть его имя myEvent. Ключевое слово event сообщает компилятору о том, что это не публичное поле, а специальным образом раскрывающаяся конструкция, скрывающая от программиста детали реализации механизма событий (пока это замечание пропустите).
В C# разрешается формировать какие угодно разновидности событий. Но ради совместимости программных компонентов со средой .NET Framework следует придерживаться рекомендаций, которые по существу, сводятся к следующему требованию: у обработчиков событий должны быть два параметра. Первый из них — ссылка на объект, формирующий событие, второй — параметр типа EventArgs, содержащий любую дополнительную информацию о событии, которая требуется обработчику. То есть:
void обработчик(object отправитель, EventArgs е)
Как правило, отправитель — это параметр, передаваемый вызывающим кодом с помощью ключевого слова this. Параметр е типа EventArgs содержит дополнительную информацию о событии и может быть проигнорирован, если он не нужен.
Отметим, что и в первом примере с кнопкой автоматически сгенерировался заголовок метода, обеспечивающего обработку клика мышкой:
private void button1_Click(object sender, EventArgs e)
Сам класс EventArgs не содержит полей, которые могут быть использованы для передачи дополнительных данных обработчику, он служит в качестве базового класса, от которого получается производный класс, содержащий все необходимые поля. Тем не менее, в классе EventArgs имеется одно поле Empty типа static, которое представляет собой объект типа EventArgs без данных.
В среде .NET Framework предоставляется встроенный обобщенный делегат под названием EventHandler<TEventArgs>. В данном случае тип TEventArgs обозначает тип аргумента, передаваемого параметру EventArgs события.
Для обработки многих событий параметр типа EventArgs оказывается ненужным. Поэтому с целью упрощения создания кода в подобных ситуациях в среду .NET Framework и был внедрен необобщенный делегат типа EventHandler, используемый для объявления обработчиков событий, которым не требуется дополнительная информация о событиях (см. наш первый пример).
Пример использования обобщенного делегата EventHandler<TEventArgs>
Обобщенный делегат EventHandler<MyEA> используется для
объявления события Ez:
public event EventHandler<MyEA> Ez;
Аргументы, передаваемые в метод, задаются в классе MyEA, который наследуется от класса EventArgs.
Постановка задачи «Управление размерами и цветом формы»
Набор цветов: Red, Green, Blue, Yellow + исходный (добавляйте любые!)
Размеры: 500х150, 550×200, 600×250, 650×300
Элементы управления:
Кнопка button1 — Разрешение/Запрет изменение свойств формы
Кнопка button2 — Перекраска формы в желтый цвет без ограничений
Элемент comboBox1 — для выбора цвета: Red, Green, Blue, прежний
Метка label1 — подсказка: «Выберите цвет закраски формы» к comboBox1.
Начальная форма может выглядеть так:

Создаются два класса:
1) Класс Моих Событий Аргументы:
2) Мой класс Обработка события:
Далее приводится текст файла Form1.cs с комментариями:
Вид формы после перекраски:

Примеры
Другой пример применения делегатов рассмотрен в посте «Делегаты и методы».
NEW: Наш Чат, в котором вы можете обсудить любые вопросы, идеи, поделиться опытом или связаться с администраторами.
JQuery: что нужно знать об обработке событий

JQuery – бесплатная библиотека, которая используется при программировании на JavaScript. Она имеет открытый исходный код и используется для облегчения веб-разработки.
JQuery упрощает взаимодействие с DOM-элементами. При помощи этой библиотеки удается реализовывать обработку событий с минимальными трудностями. Именно об этом предстоит поговорить далее. Информация пригодится как разработчикам-новичкам, так и уже более опытным программистам.
Несколько слов о событии
Все действия клиентов, посещающих веб страницу, можно обработать. Такие операции носят название событий. Примеры:
- передвижение курсора через имеющийся элемент;
- нажатие на тот или иной объект веб-страницы;
- выбор радио кнопки.
Событие – это своеобразный «сигнал», который возникает в браузере. Он сообщает клиенту, что что-то произошло для дальнейшего взаимодействия.
События в DOM бывают нескольких видов. Ниже – таблица, которая показывает некоторые доступные варианты:
| События мыши | События клавиатуры | События форм | События окон и документов |
| click | keypress | submit | load |
| mouseenter | keydown | blur | unload |
| dbclick | keyup | change | resize |
| mouseleave | focus | scroll |
Далее предстоит изучить особенности обработчика событий JS, а также рассмотреть методы JQuery для обработки «происшествий».
Работа с методами JQuery
В рассматриваемой библиотеке JS повесить событие (слушатель) можно на определенный элемент. Для этого используются две функции:
- on;
- one.
Первый вариант используется еще и для более краткой записи операции.
Выше – наглядный пример работы со слушателем. Перед тем как переходить к добавлению элементам обработчиков, потребуется сначала их получить. Для этого используется селектор. В него передается соответствующая функция (selector). Результатом становится набор найденных элементов в формате объекта jQuery.
Метод on используется для присоединения одного или нескольких «слушателей» к заданному элементу. One работает аналогичным образом, но отличается тем, что выполнение обработчика происходит всего один раз при наступлении заданного «происшествия».
Метод on ()
Метод on () в рассматриваемой библиотеке JS используется для присоединения к выбранным элементам функции обработчика событий. Применяется не только к одной «операции», но и к нескольким.
Синтаксис будет следующим:
Это – вариант для назначения функции одного или нескольких событий. Здесь:
- events – это типы событий, которые будут обрабатываться;
- selector – селектор, по которому происходит фильтрация элементов, находящихся внутри уже обнаруженных;
- data – данные, передаваемые непосредственно обработчику событий (они размещаются в переменной event .data);
- handler – функция, установленная в качестве обработчика.
Если вместо handler указать значение false, оно укажет на реализацию функции типа function ()
С помощью метода on () можно установить на выбранные элементы сразу несколько разных слушателей. Каждый из них будет реагировать на заданный тип события. Форма представления такой записи будет следующей:
- eventMap – это объект, в котором необходимо перечислить типы обрабатываемых событий и соответствующие им слушатели;
- selector – селектор для фильтрации;
- data – информация, которая будет передаваться слушателю.
А вот простой пример использования метода on в jQuery:
Этот метод появился в библиотеке в версии 1.7. Помог объединить три ранее существующих метода обработки «происшествий» на элементах HTML страницы: blind, live и delegate.
Убрать обработчик можно при помощи метода off, а для его срабатывания всего один раз – только через метод one.
Типы обрабатываемых событий
В виде первого параметра метода (типа) допускается использование любого строкового значения. При необходимости обработки одного из стандартных javascript-событий, рекомендуется пользоваться «обычными» обозначениями:
- error;
- unload;
- change;
- select и другими.
Каждый соответствующий тип обладает одноименным методом, который выступает краткой формой on(). Пример – использование click (handler). Такая запись равноценна on («click», handler).
Когда тип события не совпадает ни с одним из имеющихся значений, оно будет рассматриваться библиотекой как пользовательское. Такие элементы будут организованы пользователями путем генерации через методы trigger и triggerHandler.
Пространства имен
Тип «происшествий» иногда задается с указанием пространства имен. Пример – on (‘click.name’, handler). Здесь:
- name – это именное пространство;
- click – тип «происшествия».
Пространство имен – это элемент, который позволяет делить обработчики одних и тех же событий на подгруппы. Их можно будет легко вызвать через метод trigger или удалить через off.
Допускается указание сразу нескольких именных пространств для выбранного элемента. Они пишутся через точку. Для обращения к таким «операциям» достаточно указать одно из них. Именные пространства напоминают классы в CSS.
Прямая и делегированная обработка
Если параметр selector не указан или имеет значение NULL, обработчик будет установлен на выбранные элементы. Он сработает тогда, когда произошло действие, непосредственно на соответствующих компонентах или «поднялось» от их потомков. Такой процесс называется прямым.
У непосредственной обработки есть недостатки. Пример – на странице имеет список (ul), на элементах которого должен срабатывать click. Если при установке соответствующих слушателей в список добавляются новые составляющие, они не будут реагировать на «клики». Связано это с тем, что связи с элементами устанавливались тогда, когда «нововведения» еще не существовали. Из-за этого не исключено возникновение большого количества логических ошибок.
В jQuery для таких ситуаций придумана делегированная обработка событий. Здесь вместо заданного слушателя библиотека установит собственный специальный. Он не установится непосредственно на элементы, для которых используется слушатель (пусть такие «происшествия» называются inner элементы), а на содержащие их элементы (outer). Получится, что inner расположен внутри outer.
Как только событие происходит на одном из элементов inner, оно будет подниматься вверх по DOM-иерархии В какой-то момент этот компонент попадает в один из outer. На нем сработает специально установленный слушатель. Начнется проверка на поднятие от одного из inner элементов. Если это так, запустится обработчик handler.
Когда использованы методы делегированной обработки, добавление новых inner элементов внутрь outer не будет нарушать работоспособность всего скрипта. События будут обрабатываться исправно, даже если они возникают в новых компонентах.
Для организации делегированной обработки потребуется во втором параметре метода on() установить селектор. Тогда:
- outer элементы – это элементы, к которым применен выбранный метод;
- inner элементы – компоненты, расположенные внутри outer, а также удовлетворяющие заданному селектору.
Выше – наглядный пример в случае с click.
Чем выше то или иное событие располагается в иерархии, тем больше вычислительных ресурсов потребуется для его обработки.
В браузерах событие load не всплывает вверх по иерархии, как и focus, blur. В Internet Explorer до 8 версии paste и reset тоже не имеют соответствующего свойства. Именно поэтому для них привязывать слушатели необходимо прямо на элементы, для которых генерируются «действия». От делегирования придется отказаться.
Обработчики
В виде параметра handler необходимо указывать функцию или значение false. Пример – анонимная функция:
Допускается задание имени используемой функции:
Когда происходит событие, библиотека передает в слушатель объект event (в нем содержатся дополнительные данные по «происшествию»). Соответствующий элемент отличается от стандартных, предоставляемых браузерами. В jQuery меняются некоторые поля для обеспечения кроссбраузерности. Это позволяет добраться до нативного объекта события. Он будет расположен в поле event.originalEvent.
Событие после появления будет всегда всплывать по иерархии DOM до объекта document. Если в процессе обработки события всплытие нужно остановить, это делается через метод stopPropagation(). Он пишется внутри слушателя. Результатом станет то, что соответствующее событие прекратит дальнейшее всплытие по дереву DOM. Если в текущем элементе присутствовали иные невыполненные обработчики, они будут реализованы. Для исключения данной ситуации потребуется вместо stopPropagation использовать stopImmediatePropagation.
События могут порождать связанные с ними действия. Пример – сразу после того, как пользователь нажал на ссылку, происходит переход на другую страничку. Для отмены соответствующий операций внутри обработчика можно вызвать event. preventDefault.
Допускается указание false вместо параметра. В этом случае event.stopPropagation и event.preventDefault вызываются автоматически. Форма представления метода:
Здесь при нажатии по ссылкам с классом disabled не происходит переход на другие страницы. Событие не передается родительским элементам.
Внутри обработчика переменная this всегда включает в себя DOM элемент, на котором событие отлавливается. Во время прямой обработки им станет один из выбранных элементов, при делегированной – компонент, находящийся внутри одного из выбранных элементов, а также удовлетворяющий параметру selector. Создание объекта jQuery по this-компоненту возможно так: $(this).
Дополнительные данные для слушателя
При изучении on событий в jQuery можно передавать в «происшествия» дополнительные данные. Для этого используется параметр data. Если он задан, то соответствующий элемент станет доступным в обработчике в event.data.
Данный параметр поддерживает передачу информации любого типа, но следует быть аккуратнее при работе со строками. Если передается string, а селектор не установлен, библиотека рассмотрит соответствующий объект в качестве selector-параметра. Исправить ситуацию удается при помощи присваивания null имеющемуся селектору. Data можно задать через объекты. С их помощью слушатель сможет передавать сразу много информации.
Кроме data передать дополнительные параметры в обработчик можно через ручной вызов события методами trigger и triggerhandler.
Метод one
Метод one является единственным в библиотеке, используемым для однократной обработки событий. Он устанавливает слушатель на элементы страницы. В каждом из них он может быть вызван не более одного раза.
Форма представления метода:
- eventType – тип события, подлежащего обработке;
- eventData –передаваемые данные;
- handler (eventObject) – функция, которая устанавливается в качестве слушателя.
Выше – пример установки обработчика через метод one. Убрать его получится при помощи unbind().
Дополнительная информация о событии
При обработке «происшествий» о нем можно получить дополнительную информацию. Соответствующие данные передаются в качестве первого аргумента объекта Event.
Выше – пример кода, который поможет вывести дополнительную информацию о том или ином событии.
Как быстро выучить
JQuery – достаточно функциональная библиотека. Выучить ее самостоятельно с нуля бывает проблематично, особенно новичкам. Чтобы быстрее разобраться с JS и его инструментами, рекомендуется закончить специализированные компьютерные курсы. Пример – от образовательного центра OTUS.
Их преимущества – это:
- Сжатые сроки обучения и грамотно составленная программа. Выбранное направление можно освоить в период до 12 месяцев.
- Постоянное кураторство и организация занятий полностью через интернет. Учебу легко совмещать с работой, семьей и даже хобби.
- Разнообразие направлений. Интересные предложения будут найдены не только для новичков, но и для уже опытных программистов.
- Возможность освоить не только JS и jQuery, но и другие языки разработки «с нуля».
- Интересные домашние и практические задания.
В конце каждого успешно завершенного курса ученики будут получать электронные сертификаты. Это документальное подтверждение приобретенных знаний и навыков в выбранном направлении.