Привязка события к кнопке javascript. События и обработчики событий в JavaScript. Использование библиотеки jQuery

В данном уроке мы с вами разберем все способы работы с событиями в JavaScript.

События через атрибуты

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

Напомню еще раз этот способ на примере: сейчас по клику на кнопку сработает функция func , которая выводит на экран alert :

Задания события через атрибут имеет свои недостатки: если, к примеру, я хочу ко всем инпутам на странице привязать определенное событие - мне придется полазить по HTML странице, найти все инпуты и каждому добавить атрибут с событием. Это не очень удобно и хотелось бы иметь под рукой более продвинутый способ работы с событиями.

Поэтому давайте посмотрим, что еще нам может предложить JavaScript при работе с событиями.

События через работу с атрибутами

По сути атрибут onclick является таким же атрибутом, как, к примеру, value . И, если мы могли менять атрибут value таким образом - elem.value , то точно также мы можем менять атрибут onclick .

Если мы сделаем так: elem.onclick = func , то привяжем к элементу elem функцию func . Посмотрите пример и под ним мы обсудим все нюансы этого способа:

var elem = document.getElementById("test"); elem.onclick = func; function func() { alert("!"); }

Теперь я должен открыть вам страшную тайну JavaScript: если функция написана без круглых скобок, например func , то она возвращает свой исходный код , а если с круглыми скобками, например func() , то возвращает результат работы функции.

Я уверен, что прочитав это, вы не до конца поймете то, что я хотел вам донести, поэтому запустите пример и еще раз перечитайте предыдущий абзац. Вот пример:

//Функция возвращает строку "!" function func() { return "!"; } alert(func()); //вы увидите строку "!" alert(func); //а сейчас вы увидите исходный код функции func!

Теперь, зная эту страшную тайну, вернемся к строке elem.onclick = func - в данном случае я в атрибут onclick записываю исходный код функции, а не ее результат - и все работает. Если вы сделаете так - elem.onclick = func() - то запишите результат функции и ничего не будет работать.

Кстати, результатом функции func() будет undefined , так как у нее нет команды return . Напомню код функции, о которой идет речь:

function func() { alert("!"); }

Давайте вспомним метод setInterval (см. урок работа с таймерами в JavaScript), когда мы использовали его таким образом window.setInterval(timer, 1000) - в этом случае мы также писали функцию timer без круглых скобок, потому что нас интересовал не результат работы функции, а ее код .

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

Достоинства и недостатки такого способа

Давайте теперь обсудим достоинства и недостатки этого способа.

Достоинства

Достоинства такие: теперь, если мы захотим задать одновременно одно событие всем инпутам на странице, нет нужды вручную прописывать каждому из них атрибут с событием. Можно просто получить все инпуты, перебрать их циклом и каждому привязать событие.

Давайте сделаем это. Получим все инпуты с помощью getElementsByTagName и в цикле привяжем каждому такое событие: пусть по клику каждый инпут выдает алертом текст "!":

/* Этот код будет запускаться по загрузке страницы. Напоминаю, что писать его нужно после HTML кода. */ var elems = document.getElementsByTagName("input"); for (var i = 0; i < elems.length; i++) { elems[i].onclick = func; } function func() { alert("!"); }

Теперь нажатие на любой инпут будет приводить к тому, что будет срабатывать функция func , которая алертом выводит "!".

Использование this

Давайте усложним задачу и сделаем так, чтобы alert выводил содержимое атрибута value того инпута, на который кликнули мышкой.

Для этого нужно воспользоваться this , только не так, как мы это делали раньше. Раньше, когда мы писали событие прямо в атрибут, мы делали так: onclick="func(this)" , однако сейчас вот так - elems[i].onclick = func(this) - мы сделать не можем .

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

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

Вы можете спросить, почему тут - onclick="func()" - в функции написаны круглые скобки, хотя по логике там тоже требуется исходный код, а не результат. Об этом вы узнаете в уроке про анонимные функции чуть позже.

Так как правильно использовать this в нашей конструкции elems[i].onclick = func ? На самом деле тут this доступен внутри функции func и он ссылается на тот элемент, в котором возникло событие, вызвавшее эту функцию. То есть, если я делаю клик по первому инпуту - в this будет лежать ссылка на него, а если по второму - то на него.

В данном случае считайте, что this - это будто переменная elem , полученная через getElementById . К примеру, elem.value позволяет обратиться к атрибуту value , значит this.value будет делать то же самое.

Итак, давайте все-таки решим нашу задачу - сделаем так, чтобы alert выводил содержимое атрибута value того инпута, на который кликнули мышкой:

< elems.length; i++) { elems[i].onclick = func; } function func() { alert(this.value); //изменение только здесь }

Учтите, что если вы попытаетесь воспользоваться this внутри функции, которая была прописана прямо в атрибуте (то есть первым способом задать событие) - у вас ничего не выйдет. Смотрите пример неправильного кода:

function func() { alert(this.value); //не выведет ожидаемого }

В данном случае контекст выполнения таков, что this ссылается на window , а не на текущий элемент. Почему так - поговорим, когда вы разберете анонимные функции.

Напоминаю правильный вариант:

function func(elem) { alert(elem.value); //выведет содержимое атрибута value }

Недостатки

Теперь поговорим о недостатках . Недостатком такого способа будет то, что мы можем привязать к событию только одну функцию. Если попытаться сначала записать одну функцию, а потом другую - у нас ничего не получится.

В следующем примере мы пытаемся привязать к событию onclick сразу две функции func1 и func2 . Однако по клику на элемент сработает только вторая функция, так как она затрет первую:

var elem = document.getElementById("test"); elem.onclick = func1; //тут мы сначала привязали func1 elem.onclick = func2; //а теперь func2 и func1 уже не привязана function func1() { alert("1"); } function func2() { alert("2"); }

В принципе, эту проблему легко обойти, если ввести еще и третью функцию func3. Привяжем к атрибуту onclick только func3, а она пусть вызывает func1 и func2 у себя внутри:

var elem = document.getElementById("test"); elem.onclick = func3; //тут привязывается только функция func3 //func3 вызывает func1 и func2: function func3() { func1(); func2(); } function func1() { alert("1"); } function func2() { alert("2"); }

Как вы видите, этот недостаток не слишком существенный и его легко обойти. Только что вводится лишняя функция, что немного неудобно.

Однако, есть еще один недостаток - мы не можем легко отвязать от onclick, к примеру, только функцию func1, оставив func2 привязанным. Можно, конечно же, накрутить большие конструкции кода, однако это не нужно, если пользоваться еще более продвинутым способом привязать событие - через addEventListener. Давайте посмотрим, как с работать с этой функцией:

Работа с addEventListener

Метод addEventListener первым параметром принимает название события, а вторым - функцию, которую нужно привязать к этому событию. При этом имя события пишется без "on": "click" вместо "onclick", "mouseover" вместо "onmouseover" и так далее. Имя функции (второй параметр) пишется без кавычек и без круглых скобок (зачем это нужно, мы с вами уже разобрали выше).

Давайте сделаем так, чтобы по клику на кнопку вызывалась функция func:

var elem = document.getElementById("test"); elem.addEventListener("click", func); function func() { alert("!"); }

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

var elem = document.getElementById("test"); elem.addEventListener("click", func1); elem.addEventListener("click", func2); function func1() { alert("1"); } function func2() { alert("2"); }

Если вы скопируете этот код и запустите его у себя - сработает и функция func1, и функция func2.

Работа с this для addEventListener

Мы с вами уже разбирали работу с this в случае, если привязывать события вторым способом (через свойство элемента). В случае с addEventListener this работает аналогичным образом - он будет ссылаться на тот элемент, в котором случилось событие.

Давайте посмотрим на примере: привяжем к кнопке событие onclick , которое будет запускать функцию func . Эта функция будет выводить на экран value нашей кнопки:

var elem = document.getElementById("test"); elem.addEventListener("click", func); function func() { alert(this.value); }

С одной кнопкой не очень интересно проверять работу this . Давайте сделаем две кнопки, привязав в ним одну и ту же функцию func . В этом случае функция func будет выводить value той кнопки, на которую мы кликнули:

var elem1 = document.getElementById("test1"); elem1.addEventListener("click", func); var elem2 = document.getElementById("test2"); elem2.addEventListener("click", func); function func() { alert(this.value); }

Здесь удобство работы с this в том, что не нужно создавать разные функции для разных элементов. Есть одна функция func , которая делает одно и то же, но для разных элементов и различаем мы их через this - на какой элемент кликнули - тот элемент и будет в this .

Ну, а сейчас получим массив кнопок с помощью getElementsByTagName и каждой из них привяжем функцию func.

var elems = document.getElementsByTagName("input"); for (var i = 0; i < elems.length; i++) { elems[i].addEventListener("click", func); } function func() { alert(this.value); }

Удаление привязки через removeEventListener

Сейчас мы с вами займемся тем, что будем удалять привязанные к событию функции. Что у нас будет получаться: если, к примеру, к событию onclick привязаны функции func1 и func2 , то мы сможем отвязать функцию func1, не затрагивая func2 и наоборот.

Давайте привяжем к элементу 3 функции: func1, func2 и func3, которые будут выводить на экран числа 1, 2 и 3:

var elem = document.getElementById("test"); elem.addEventListener("click", func1); elem.addEventListener("click", func2); elem.addEventListener("click", func3); function func1() { alert("1"); } function func2() { alert("2"); } function func3() { alert("3"); }

А теперь сразу же после привязки отвяжем функции func1 и func2. Это делается с помощью метода removeEventListener , которая принимает те же параметры, что и addEventListener:

var elem = document.getElementById("test"); elem.addEventListener("click", func1); elem.addEventListener("click", func2); elem.addEventListener("click", func3); elem.removeEventListener("click", func1); elem.removeEventListener("click", func2); function func1() { alert("1"); } function func2() { alert("2"); } function func3() { alert("3"); }

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

Обработка событий

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

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

Тип события - это строка, определяющая тип действия, вызвавшего событие. Тип «mousemove», например, означает, что пользователь переместил указатель мыши. Тип «keydown» означает, что была нажата клавиша на клавиатуре. А тип «load» означает, что завершилась загрузка документа (или какого-то другого ресурса) из сети. Поскольку тип события - это просто строка, его иногда называют именем события.

Цель события - это объект, в котором возникло событие или с которым это событие связано. Когда говорят о событии, обычно упоминают тип и цель события. Например, событие «load» объекта Window или событие «click» элемента . Самыми типичными целями событий в клиентских приложениях на языке JavaScript являются объекты Window, Document и Element, но некоторые типы событий могут происходить и в других типах объектов.

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

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

Для каждого типа события в связанном объекте события определяется набор свойств. Например, объект, связанный с событиями от мыши, включает координаты указателя мыши, а объект, связанный с событиями от клавиатуры, содержит информацию о нажатой клавише и о нажатых клавишах-модификаторах. Для многих типов событий определяются только стандартные свойства, такие как type и target, и не передается никакой дополнительной полезной информации. Для таких типов событий важно само наличие происшествия события, и никакая другая информация не имеет значения.

Распространение события - это процесс, в ходе которого браузер решает, в каких объектах следует вызвать обработчики событий. В случае событий, предназначенных для единственного объекта (таких как событие «load» объекта Window), надобность в их распространении отсутствует. Однако, когда некоторое событие возникает в элементе документа, оно распространяется, или «всплывает», вверх по дереву документа.

Если пользователь щелкнет мышью на гиперссылке, событие «mousemove» сначала будет возбуждено в элементе , определяющем эту ссылку. Затем оно будет доставлено вмещающим элементам: возможно, элементу

Элементу и самому объекту Document. Иногда удобнее бывает зарегистрировать единственный обработчик события в объекте Document или в другом контейнерном элементе, чем выполнять регистрацию во всех интересующих нас элементах.

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

Регистрация обработчиков событий

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

Дело осложняется тем, что каждый прием имеет две версии. Свойство обработчика события можно установить в программном коде на языке JavaScript или в элементе документа, определив соответствующий атрибут непосредственно в разметке HTML. Регистрация обработчиков вызовом метода может быть выполнена стандартным методом с именем addEventListener(), который поддерживается всеми браузерами, кроме IE версии 8 и ниже, и другим методом, с именем attachEvent(), поддерживаемым всеми версиями IE до IE9.

Установка свойств обработчиков событий

Самый простой способ зарегистрировать обработчик события заключается в том, чтобы присвоить свойству целевого объекта события желаемую функцию обработчика. По соглашению свойства обработчиков событий имеют имена, состоящие из слова «on», за которым следует имя события: onclick, onchange, onload, onmouseover и т.д. Обратите внимание, что эти имена свойств чувствительны к регистру и в них используются только строчные символы, даже когда имя типа события состоит из нескольких слов (например «readystatechange»). Ниже приводятся два примера регистрации обработчиков событий:

// Присвоить функцию свойству onload объекта Window. // Функция - обработчик события: она вызывается, когда документ будет загружен window.onload = function() { // Отыскать элемент var elt = document.getElementById("shipping_address"); // Зарегистрировать обработчик события, который будет вызываться // непосредственно перед отправкой формы elt.onsubmit = function() { return validate(this); } }

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

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

Установка атрибутов обработчиков событий

Свойства обработчиков событий в элементах документа можно также устанавливать, определяя значения атрибутов в соответствующих HTML-тегах. В этом случае значение атрибута должно быть строкой программного кода на языке JavaScript. Этот программный код должен быть не полным объявлением функции обработчика события, а только ее телом. То есть реализация обработчика события в разметке HTML не должна заключаться в фигурные скобки и предваряться ключевым словом function. Например:

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

Некоторые типы событий предназначены для браузера в целом, а не для какого-то конкретного элемента документа. Обработчики таких событий в языке JavaScript регистрируются в объекте Window. В разметке HTML они должны помещаться в тег , но браузер зарегистрирует их в объекте Window. Ниже приводится полный список таких обработчиков событий, определяемых проектом спецификации HTML5:

onafterprint onfocus ononline onresize onbeforeprint onhashchange onpagehide onstorage onbeforeunload onload onpageshow onundo onblur onmessage onpopstate onunload onerror onoffline onredo

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

addEventListener()

В стандартной модели событий, поддерживаемой всеми браузерами, кроме IE версии 8 и ниже, целью события может быть любой объект - включая объекты Window и Document и все объекты Elements элементов документа - определяющий метод с именем addEventListener() , с помощью которого можно регистрировать обработчики событий для этой цели.

Метод addEventListener() принимает три аргумента. Первый - тип события, для которого регистрируется обработчик. Тип (или имя) события должен быть строкой и не должен включать префикс «on», используемый при установке свойств обработчиков событий. Вторым аргументом методу addEventListener() передается функция, которая должна вызываться при возникновении события указанного типа. В последнем аргументе методу addEventListener() передается логическое значение. Обычно в этом аргументе передается значение false. Если передать в нем значение true, функция будет зарегистрирована как перехватывающий обработчик и будет вызываться в другой фазе распространения события.

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

Следующий фрагмент регистрирует два обработчика события «click» в элементе . Обратите внимание на различия двух используемых приемов:

Щелкните меня! var b = document.getElementById("mybutton"); b.onclick = function() { alert("Спасибо, что щелкнули на мне!"); }; b.addEventListener("click", function() {alert("Еще раз спасибо!")}, false);

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

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

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

Internet Explorer версии ниже IE9 не поддерживает методы addEventListener() и removeEventListener(). В версии IE5 и выше определены похожие методы, attachEvent() и detachEvent() . Поскольку модель событий в IE не поддерживает фазу перехвата, методы attachEvent() и detachEvent() принимают только два аргумента: тип события и функцию обработчика, при этом в первом аргументе методам в IE передается имя свойства обработчика с префиксом «on», а не тип события без этого префикса.

Вызов обработчиков событий

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

Аргумент обработчика событий

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

В IE версии 8 и ниже обработчикам событий, зарегистрированным установкой свойства, объект события при вызове не передается. Вместо этого объект события сохраняется в глобальной переменной window.event. Для переносимости обработчики событий можно оформлять, как показано ниже, чтобы они использовали переменную window.event при вызове без аргумента:

Объект события передается обработчикам событий, зарегистрированным с помощью метода attachEvent(), но они также могут использовать переменную window.event.

При регистрации обработчика события посредством HTML-атрибута браузер преобразует строку с программным кодом на языке JavaScript в функцию. Браузеры, отличные от IE, создают функцию с единственным аргументом event. В IE создается функция, не принимающая аргументов. Если в таких функциях использовать идентификатор event, он будет ссылаться на window.event. В любом случае обработчики событий, определяемые в разметке HTML, могут ссылаться на объект события, используя идентификатор event.

Контекст обработчиков событий

Когда обработчик событий регистрируется установкой свойства, это выглядит как определение нового метода элемента документа:

E.onclick = function() { /* реализация обработчика */ };

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

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

/* Регистрирует указанную функцию как обработчик событий указанного типа в указанном объекте. Гарантирует, что обработчик всегда будет вызываться как метод целевого объекта. */ function addEvent(target, type, handler) { if (target.addEventListener) target.addEventListener(type, handler, false); else target.attachEvent("on" + type, function(event) { // Вызвать обработчик как метод цели, // и передать ему объект события return handler.call(target, event); }); }

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

Возвращаемые значения обработчиков

Значение, возвращаемое обработчиком события, зарегистрированным установкой свойства объекта или с помощью HTML-атрибута, следует учитывать. Обычно возвращаемое значение false сообщает браузеру, что он не должен выполнять действия, предусмотренные для этого события по умолчанию.

Например, обработчик onclick кнопки отправки формы может вернуть false, чтобы предотвратить отправку формы браузером. (Это может пригодиться, если ввод пользователя не прошел проверку на стороне клиента.) Аналогично обработчик события onkeypress поля ввода может фильтровать ввод с клавиатуры, возвращая false при вводе недопустимых символов.

Также важно значение, возвращаемое обработчиком onbeforeunload объекта Window. Это событие генерируется, когда браузер выполняет переход на другую страницу. Если этот обработчик вернет строку, она будет выведена в модальном диалоговом окне, предлагающем пользователю подтвердить свое желание покинуть страницу.

Важно понимать, что учитываются значения, возвращаемые обработчиками событий, только если обработчики зарегистрированы посредством установки свойств. Обработчики, зарегистрированные с помощью addEventListener() или attachEvent() вместо этого должны вызывать метод preventDefault() или устанавливать свойство returnValue объекта события.

Отмена событий

Значение, возвращаемое обработчиком события, зарегистрированным как свойство, можно использовать для отмены действий, выполняемых браузером по умолчанию в случае этого события. В браузерах, поддерживающих метод addEventListener(), отменить выполнение действий по умолчанию можно также вызовом метода preventDefault() объекта события. Однако в IE, версии 8 и ниже, тот же эффект достигается установкой свойства returnValue объекта события в значение false.

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

Window.onload = function() { // Найти все ссылки var a_href = document.getElementsByTagName("a"); // Добавить обработчик события click (не для IE

Текущий проект модуля «DOM Events 3» определяет в объекте Event свойство с именем defaultPrevented . Оно пока поддерживается не всеми браузерами, но суть его в том, что при обычных условиях оно имеет значение false и принимает значение true только в случае вызова метода preventDefault().

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

В IE версии 8 и ниже метод stopPropagation() не поддерживается. Вместо этого объект события в IE имеет свойство cancelBubble . Установка этого свойства в значение true предотвращает распространение события.

Текущий проект спецификации «DOM Events 3» определяет в объекте Event еще один метод - метод с именем stopImmediatePropagation() . Подобно методу stopPropagation(), он предотвращает распространение события по любым другим объектам. Но кроме того, он также предотвращает вызов любых других обработчиков событий, зарегистрированных в том же объекте.

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

Что такое событие и обработчики событий

Событие - это некое действие, которое может производить либо пользователь, либо другие объекты на странице.

Самым ярким примером события это клик пользователя по какому-то объекту(click ), будь то это кнопка, ссылка или любой другой элемент. Другой пример события, это наведение мыши над каким-то объектом(mouseover ), скажем над изображением. Также событием является полное загрузка страницы(load ). В общем все действия, которые происходят на сайте являются событиями.

Так вот, мы можем захватить любое событие, которое производится на странице и обрабатывать её с помощью соответствующего обработчика. Например, при наведении мыши на какой-то блок div, мы можем вывести некое сообщение, допустим "Вы находитесь в текстовой области". Или, при клике по кнопке скрыть какой-то блок со страницы. В общем, много чего можно сделать пре обработки какого-то события.

И для того чтобы обрабатывать какое-то событие, необходимо использовать специальный обработчик для данного события. Каждое событие имеет свой обработчик, например, у события клик(click ) есть обработчик onclick . У события наведения мыши над объектом(mouseover ) есть обработчик onmouseover . И у события полной загрузки страницы(load ) есть обработчик onload .

То есть как вы поняли название обработчика , формируется из префикса "on" + название события.

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

Обработчик события вызывается в качестве атрибута, в самом теге HTML элемента. В значение обработчика можно написать сразу код JavaScript, но лучше вызывать какую-то функцию, которая сделает необходимые действия. Функцию необходимо описать внутри тега script, который может находится как внутри блока head, так и в конце тега body. В качестве параметра для этой функции передаётся слово this , то есть текущий объект.

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

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry"s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.

Div{ padding-left: 50px; width: 200px; border: 1px solid #000; }

JavaScript код:

Function blockOver(block){ alert("Вы находитесь в текстовой области "); }

Сохраняем документ, открываем его в браузере, наводим курсор мыши над текстом и видим результат обработки данного события:


Как получить значение атрибута в javascript ?

С помощью параметра функций (this), можно получить значение какого-то атрибута текущего объекта , например, узнать его id.

Для примера, создадим кнопку и зададим ей id со значением "justButton". Когда кликнем на данную кнопку, то выведем такое сообщение: "Вы кликнули по кнопке, с идентификатором значение_id". Здесь необходимо уже использовать обработчик onclick .

JavaScript код:

Function clickOnButton(button){ alert("Вы кликнули по кнопке, с идентификатором: " + button.id); }

Сохраняем документ, открываем его в браузере и кликаем по кнопке.


Таким же образом можно вывести имя кнопки(button.name ) или её значение(button.value )

Получаем значение ширины и высоты элемента

Ещё можно узнать значения CSS свойства элемента , например, ширину и высоту. Для получения ширины используются свойства clientWidth и offsetWidth , а для высоты clientHeight и offsetHeight . Для примера, выведем значения ширины и высоты кнопки, по которой кликнули.

Теперь содержимое функции clickOnButton будет такой:

Function clickOnButton(button){ //alert("Вы кликнули по кнопке, с идентификатором: " + button.id); var width = button.clientWidth || button.offsetWidth; var height = button.clientHeight || button.offsetHeight; alert("Ширина кнопки: " + width + "\nВысота кнопки: " + height); }

Результат данного примера:


Напоминаю, что ширина элемента считается вместе со значением padding, поэтому она и равна 111px [ 99px(width) + 6px(padding-left) + 6px(padding-right) ].

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

Например, при загрузке страницы можно вывести сообщение о том, что "страница загружается". Для этого необходимо использовать событие load и её обработчик onload . Данный обработчик напишем в открывающем теге body.

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

И в конец данной статьи разберём простой пример обработки формы. Обработка формы на JavaScript, во-первых, уменьшает загрузку на сервер и во-вторых придаёт дополнительный плюс к юзабилити сайта.

Форма состоится из одного поля для логина, и кнопки отправить. При отправке формы, будем проверять длину логина. Его длина должна быть больше трёх символов.

Начнём, мы с HTML структуры данной формы.

Теперь, тегу формы добавим в качестве атрибута обработчик onsubmit , события submit . Следующим образом:

Событие submit срабатывает при отправке формы. Оператора return мы написали для того чтобы запретить отправку формы, в случае обнаружения ошибки в вводе данных. Если функция вернёт значение false, то значение обработчика onsubmit будет «return false», это значит, что форма не отправиться на сервер. В противном случае, если форма вернёт true, то значение обработчика будет «return true» и форма отправится без проблем.

Иногда бывает необходимо чтобы полностью запретить отправку формы, в таком случае значение обработчика onsubmit будет таким:

Onsubmit = "checkForm(this); return false;"

Как Вы наверняка уже догадались, checkForm это название функции, которая вызовется, когда сработает событие submit. Вы можете назвать её как хотите, следуя правилам наименования функции.

И так, вернёмся к нашему примеру. Теперь нам необходимо описать функцию checkForm. В ней будет такое условие: если длина логина меньше трёх символов, то мы возвращаем false и форма не отправится, в противном случае, если данные были введены правильно, то, мы отправляем форму на сервер.

Function checkForm(form){ //Получаем значение поля формы, у которой name равен login var login = form.login.value; //Проверяем, если длина логина меньше трёх символов то выводим сообщение об ошибке и отменяем отправку формы. if(login.length > 3){ alert("Длина логина должна быть больше трёх символов"); return false; }else{ return true; } }

Сохраняем документ, открываем его в браузере и тестируем.


Таким вот образом можно проверить форму на языке JavaScript и отменить её отправку в случае ошибки.

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

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

Задачи
  • Создайте простой калькулятор сложения цифр.
    • Создайте форму с двумя числовыми полями(type="number") для ввода чисел и кнопку с надписью "Сложить"
    • При нажатии на кнопку отправить, вызовите функцию обработки данного события.
    • Внутри функции получите значения полей и методом alert, выведите результат сложения введённых чисел.
    • Сделайте так чтобы форма не отправлялось после нажатия по кнопке.
  • onСlick - это событие № 1 на экране пользователя.
    onСlick - это клик (или щелчок) пользователя по объекту.
    После каждого такого onclick-а пользователя, должно происходить ответное действие на экране. Так достигается интерактивность интерфейса и подтверждается главный принцип общения компьютера с человеком - клик, ответ, клик, ответ.
    На пользовательском жаргоне, событие onСlick может назваться как угодно. Как только рядовые пользователи не называют этот бедный onСlick - клацнуть, дёрнуть, кликнуть, щёлкнуть, бацнуть и т.д. … Но, суть от этого не меняется годами - если пользователь проявил активность на экране и кликнул по объекту, то - компьютер должен ему (пользователю) адекватно ответить. Это и есть onСlick .

    onclick в HTML

    Событие onСlick в любом языке имеет первостепенное значение. И, HTML сему не исключение. Оно и вестимо. Действительно, уж если после клика (onСlick ) по элементу в браузере ничего не происходит - зачем тогда вообще, что-либо программировать на сайте? Так что, onСlick - желанный гость на любом интернет-экране (или экранчике).
    Теперь, ближе к теме. Если говорить более конкретно, то наш onСlick по страничке сайта, в браузере - это событие из Ява-скрипт, для которого HTML служит всего лишь каркасом размещения кода его конструкций. И, с точки зрения валидности кода этого самого HTML - правильно будет писать onclick , а не onСlick (как привыкли многие прикладные программисты). Потому что, в HTML все теги и конструкции пишутся только в нижнем регистре.

    Нет верхнего регистра в HTML. Нет, и всё тут!!! А тем «злыдням», которые пишут в HTML в верхнем регистре, в старые добрые времена было принято рубить руки по самые колени. Более того. Говорят, что при батюшке-царе Иоанне Грозном, за запись в HTML, вида или можно легко было угодить, если не на кол, так на виселицу. Это абсолютно точно. Щас, конечно - царедворцы и правители пошли поспокойнее. Тем не менее, при написании любого кода нужно соблюдать, хотя-бы видимость приличия. С этого места и начинается повествование о правильном онклике .

    Итак, решено и доказано (для HTML).
    Первым делом, пишем onclick , а не onСlick !!!

    МЕНЮ №1
    или
    МЕНЮ №1

    Что означают сии бредовые строчки, мы будем разбираться несколько позже, а пока…
    - Принципиально, событие onclick из Ява-скрипт в HTML можно навесить на любой элемент кода HTML-страницы, будь то ,

    Или . Браузер всё «сожрёт», и всё будет работать. Вот только, доступ к элементу с клавиатуры возможен исключительно для ссылко- или кнопко- объекта. И, если предположить на мгновение, что у пользователя нет мыши и он работает исключительно с клавиатуры, то всё к чему он сможет соприкоснуться на сайте - это будут только кнопки или ссылки. Третьего не дано! Поэтому, «навешивать» событие onclick на объекты, недоступные с клавиатуры - просто некрасиво. Ну, не по-человечески, как-то это. Из сего выплывает второе правило для onclick в HTML - это событие нужно подключать только к ссылке (тег «а») или к кнопке (тег «button»). В противном случае, код работать всё-таки будет, но в аду, для таких программистов - заготовлена отдельная большая сковорода.
    Поскольку, (в HTML) форматирование и работа с кнопками («батонами») вызывает определённые трудности, то единственным, универсальным и оптимальным вариантом остаётся только ссылка (тег «а»). Но, и с этим тегом - не всё так гладко. Теперь, возвращаемся к разбору с нашей строчкой кода:

    МЕНЮ №1

    Выбрасываем из обсуждения тайтл ссылки, как совершенно очевидную вещь. Остаётся,
    МЕНЮ №1
    Вся дальнейшая писчая лабуда будет связанна с темой блокировки атрибута href , который нужно правильно «парализовать», чтобы ссылка перестала быть рабочей ссылкой, но тем не менее - выполняла функции onclick .

    return false;

    return false ; - это прямая блокировка атрибута href. Если у пользователя в браузере разрешён Ява-скрипт, то будет выполнен вызов события onclick из соответствующего скрипта, а не переход по ссылке. Т.е., чтобы при клике по «ссылке вызова» не было сразу перехода по адресу из href, в onclick добавляется событие return false; и предполагается, что сначала исполнится функция, которая отменит переход по ссылке, если javascript включен. Таким образом, содержание атрибута href не имеет никакого значения, поскольку оно игнорируется при выполнении ява-скрипта.

    Но вот вопрос. А что будет, если у пользователя в его браузере запрещён (выключен) Ява-скрипт? Как тогда поведёт себя наша ссылочка? Не буду интриговать, а сразу выложу возможные варианты развития событий - возможные значения атрибута href и соответствующего поведения браузера после клика по такой ссылке при выключенном Ява-скрипт.
    Конечно, если javascript выключен в браузере у пользователя - так это одна беда и неурядица. Если выполнение Ява-скриптов выключено (запрещено) в браузере у пользователя, то тогда начинаются сплошные проблемы с атрибутом href , поскольку тег «а», это - всё-таки ссылка и браузер будет пытаться осуществить по ней переход.

    Совсем выкинуть атрибут href из состава ссылки нельзя. Без атрибута href в тексте ссылке обойтись никак не возможно и любой валидатор сразу обидится за такое надругательство над её пряным и нежным телом. Значит, тогда остаётся один единственный вариант - наполнить атрибут href удобоваримым содержимым. Тут возможно следующее: оставить href совершенно пустым, заполнить его знаком диеза «#» или выражением javascript:// . При выключенном (или заглюканном) Ява-скрипт, после клика по таким ссылкам будет происходить следующее:

    Проба Атрибут href пустой. После клика по такой ссылке, будет просто перезагружена страница в браузере. Проба Атрибут href имеет значение "#". После клика по такой ссылке, пользователя выбросит в начало страницы, без её перезагрузки. Проба Атрибут href имеет значение "javascript://". После клика по такой ссылке, ничего не произойдёт. href="javascript://" - клик по ссылке будет просто проигнорирован браузером. Значение "javascript://" для атрибута href - это и есть стандартная «заглушка» для блокировки ссылки при выключенном Ява-скрипте.

    href="javascript://" - туфта!

    Почему туфта? Потому что, интернет-жизнь в мире поисковых систем вносит свои коррективы. С точки зрения правильной и семантической! вёрстки, абсолютно логичным будет записать в атрибут href реальную ссылку и добавить реальный тайтл для этой ссылки. Тогда, после клика по такой ссылке произойдёт одно из двух: либо, будет выполнено событие onclick из соответствующего Ява-скрипта, либо состоится переход по реальной ссылке на реальную страницу, (если Ява-скрипт отключён или заглюкал/недогрузился).

    Таким образом, подведём итоги. В ссылке вызова события Ява-скрипт, в href помещаем реальную ссылку на реальную страницу для перехода при выключенном javascript, а в onclick - функцию, вызывающую запрос выполнения скрипта при включённом Ява-скрипт.

    Иными словами, в «href» должна находиться совершенно нормальная и рабочая ссылка на любую веб-страницу, куда будет перенаправлен пользователь при клике по «ссылке вызова события» при выключенном Ява-скрипт, и которая будет игнорироваться скриптом при включенном Ява-скрипт. Вот и всё …

    Ну, и под конец -

    Проверка браузера на включение/выключение Ява-скрипт

    Стандартный код такой проверки выглядит так:
    У Вас отключён javascript...
    Где, для можно прописать в CSS любые стили, кроме display:none; и ему подобных стилей... Браузер ОБЯЗАТЕЛЬНО!!! выведет это сообщение на экран, в случае отключения пользователем Ява-скрипта в своём браузере. Таким нехитрым способом, Web-мастера часто пишут: "Включите, пожалуйста, javascript", либо выводят какие-то красивые картинки с аналогичной просьбой, либо ещё что-нибудь... Внутри тега noscript можно помещать любые HTML-теги. И, это - вовсе не лишняя предосторожность. Несмотря на то, что сейчас не так просто найти сайт, который бы вообще не использовал javascript.

    Кто не с нами, тот против нас
    Проблему с выключенным в браузере Ява-скрипт можно, вообще - решить радикально и кардинально. Например, добавить внутрь секции код HTML5, вида:




    где, http://mysite.ru/ - это веб-страница, куда сразу перенаправляется
    пользователь при выключенном в браузере Ява-скрипт.

    Некоторые программы с применением JavaScript event работают напрямую с вводимыми пользователем данными. Момент возникновения и порядок таких взаимодействий не могут быть предсказаны заранее.

    Обработчики событий

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

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

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

    Большинство программистов стараются избегать его, если это возможно.

    Самым лучшим способом считается реализация системы, которая дает коду возможность реагировать на события, когда они происходят. Браузеры реализуют ее, предоставляя возможность регистрировать функции обработчиков для конкретных JavaScript event :

    Кликните по этому документу, чтобы активировать обработчик.

    addEventListener("click", function() { console.log("You clicked!"); });

    Функция addEventListener регистрируется таким образом, что ее второй аргумент вызывается всякий раз, когда происходит событие, описанное первым аргументом.

    События и узлы DOM

    Каждый обработчик событий браузера регистрируется в контексте. При вызове функции addEventListener она вызывается как метод для всего окна, так как в браузере глобальный диапазон эквивалентен объекту window . Каждый элемент DOM имеет свой собственный метод addEventListener , который позволяет отслеживать события именно в этом элементе:

    Нажмите на меня

    Здесь нет обработчика.

    var button = document.querySelector("button"); button.addEventListener("click", function() { console.log("Button clicked."); });

    В данном примере обработчик подключен к узлу кнопки. JavaScript mouse events приводит в действие обработчик, а клик в остальной части документа — нет.

    Установив для узла атрибут onclick , мы получим тот же результат. Но узел имеет только один атрибут onclick , поэтому можно зарегистрировать для каждого узла только один обработчик. Метод addEventListener позволяет добавлять любое количество обработчиков. Так мы застрахованы от случайной замены обработчика, который уже был зарегистрирован.

    Метод removeEventListener , вызывается с аргументами, аналогичными addEventListener . Он удаляет обработчик:

    Одноразовая кнопка var button = document.querySelector("button"); function once() { console.log("Done."); button.removeEventListener("click", once); } button.addEventListener("click", once);

    Чтобы отменить функцию обработчика, мы задаем для нее имя (например, once ). Так мы передаем ее как в addEventListener , так и в removeEventListener .

    Объекты событий

    Хотя мы не упоминали об этом в приведенных выше примерах, в функции обработчиков JavaScript event передается аргумент: объект события. Он предоставляет дополнительную информацию о событии. Например, если мы хотим знать, какая клавиша мыши была нажата, нужно получить значение свойства объекта события which :

    Кликните по мне любой клавишей мыши var button = document.querySelector("button"); button.addEventListener("mousedown", function(event) { if (event.which == 1) console.log("Left button"); else if (event.which == 2) console.log("Middle button"); else if (event.which == 3) console.log("Right button"); });

    Информация, хранящаяся в объекте, различается зависимости от типа события. Свойство объекта type всегда содержит строку, идентифицирующую событие (например, «click » или «mousedown «).

    Распространение

    Обработчики событий (например, JavaScript touch events ), зарегистрированные для родительских узлов, также будут принимать события, которые происходят в дочерних элементах. Если была нажата кнопка, находящаяся внутри абзаца, обработчики событий абзаца также получат событие click .

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

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

    В следующем примере мы регистрируем обработчики «MouseDown » как для кнопки, так и для абзаца. При клике правой клавишей (JavaScript mouse events ) обработчик вызывает метод stopPropagation , который предотвращает запуск обработчика абзаца. При нажатии на кнопку другой клавишей мыши запускаются оба обработчика:

    Абзац и в нем кнопка.

    var para = document.querySelector("p"); var button = document.querySelector("button"); para.addEventListener("mousedown", function() { console.log("Handler for paragraph."); }); button.addEventListener("mousedown", function(event) { console.log("Handler for button."); if (event.which == 3) event.stopPropagation(); });

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

    Также можно использовать JavaScript event target , чтобы расширить диапазон события определенного типа. Например, если у вас есть узел, содержащий длинный список кнопок, более удобно зарегистрировать один обработчик клика для внешнего узла и использовать свойство target , чтобы отслеживать, была ли нажата кнопка, а не регистрировать экземпляры обработчика для всех кнопок:

    A B C document.body.addEventListener("click", function(event) { if (event.target.nodeName == "BUTTON") console.log("Clicked", event.target.textContent); });

    Действия по умолчанию

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

    Для большинства типов событий обработчики JavaScript event вызываются до выполнения действий по умолчанию. Если не нужно, чтобы выполнялось поведение по умолчанию, нужно вызвать для объекта события метод preventDefault .

    Его использовать для реализации пользовательских сочетаний клавиш или контекстных меню. Или, чтобы переопределить поведение, которое ожидают пользователи. Ниже приводится ссылка, по которой нельзя перейти:

    MDN var link = document.querySelector("a"); link.addEventListener("click", function(event) { console.log("Nope."); event.preventDefault(); });

    Старайтесь не делать так, если у вас нет на это веских причин.

    В зависимости от браузера некоторые события не могут быть перехвачены. В Google Chrome , например, сочетание клавиш (event keycode JavaScript ) для закрытия текущей вкладки (Ctrl-W или Command-W ) не может быть обработано с помощью JavaScript .

    События клавиш

    Когда пользователь нажимает клавишу на клавиатуре, браузер запускает событие «keydown «. Когда он отпускает клавишу, срабатывает событие «keyup «:

    Эта страница становится фиолетовой, когда вы нажимаете клавишу V.

    addEventListener("keydown", function(event) { if (event.keyCode == 86) document.body.style.background = "violet"; }); addEventListener("keyup", function(event) { if (event.keyCode == 86) document.body.style.background = ""; });

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

    В предыдущем примере использовано свойство объекта event keycode JavaScript . С его помощью определяется, какая именно клавиша была нажата или отпущена. Ноне всегда очевидно, как привести числовой код клавиши к фактической клавише.

    Для считывания значений клавиш букв и цифр используется код символа Unicode . Он связан с буквой (в верхнем регистре ) или цифрой, обозначенной на клавише. Метод charCodeAt для строк позволяет получить это значение:

    console.log("Violet".charCodeAt(0)); // → 86 console.log("1".charCodeAt(0)); // → 49

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

    Такие клавиши, как Shift , Ctrl , Alt порождают события, как обычные клавиши. Но при отслеживании комбинаций клавиш также можно определить, нажаты ли эти клавиши, по свойствам событий клавиатуры и JavaScript mouse events : shiftKey , ctrlKey , altKey и metaKey :

    Чтобы продолжить, нажмите Ctrl-Space.

    addEventListener("keydown", function(event) { if (event.keyCode == 32 && event.ctrlKey) console.log("Continuing!"); });

    События «keydown » и «keyup » предоставляют информацию о фактическом нажатии клавиш. Но что, если нам нужен сам вводимый текст? Получать текст из кодов клавиш неудобно. Для этого существует событие, «keypress «, которое срабатывает сразу после «keydown «. Оно повторяется вместе с «keydown «, пока клавиша нажата. Но только для клавиш, с помощью которых производится ввод символов.

    Свойство charCode в объекте события содержит код, который может быть интерпретирован, как код символа Unicode . Мы можем использовать функцию String.fromCharCode , чтобы преобразовать этот код в строку из одного символа.

    Установите фокус ввода на этой странице и наберите что-нибудь.

    addEventListener("keypress", function(event) { console.log(String.fromCharCode(event.charCode)); });

    Узел DOM , в котором происходит событие зависит, от того элемента, который находился в фокусе ввода при нажатии клавиши. Обычные узлы не могут находиться в фокусе ввода (если не установить для них атрибут tabindex ), но такие элементы, как ссылки, кнопки и поля формы, могут.

    Если никакой конкретный элемент не выделен фокусом ввода, то в качестве целевого узла для событий клавиши и JavaScript touch events выступает document.body .

    Клики мыши

    Нажатие клавиши мыши также приводит в действие ряд событий. События «mousedown » и «mouseup » похожи на «keydown » и «keyup «. Они запускаются, когда нажата и отпущена клавиша мыши. Данные события возникают в узлах DOM, на которые был наведен указатель мыши, когда возникло событие.

    Для общего узла, к которому относилось как нажатие, так и освобождение клавиши мыши, после события «mouseup » запускается событие «click «. Например, если нажать клавишу мыши на одном пункте, а затем переместить курсор на другой пункт и отпустить кнопку, то событие «click » будет происходить в элементе, который содержит оба эти пункта.

    Если два клика возникли близко друг к другу, также запускается событие «dblclick » (двойной клик ). Оно возникает после второго клика. Чтобы получить точную информацию о месте, где произошло событие мыши, нужно получить значение свойств pageX и pageY , которые содержат координаты события (в пикселях ) относительно левого верхнего угла документа.

    Ниже приведена реализация примитивной программы для рисования. Каждый раз при нажатии мыши в документе (под курсором ) добавляется точка:

    body { height: 200px; background: beige; } .dot { height: 8px; width: 8px; border-radius: 4px; /* закругленные углы */ background: blue; position: absolute; } addEventListener("click", function(event) { var dot = document.createElement("div"); dot.className = "dot"; dot.style.left = (event.pageX - 4) + "px"; dot.style.top = (event.pageY - 4) + "px"; document.body.appendChild(dot); });

    Свойства clientX и clientY подобны pageX и pageY , но они относятся к видимой части документа. Они могут использоваться для сравнения координат мыши с координатами, возвращаемыми функцией getBoundingClientRect .

    Движение мыши

    Каждый раз, когда перемещается курсов мыши, срабатывает событие «mousemove » из набора JavaScript mouse events . Оно может быть использовано для отслеживания положения мыши. Это применяется при реализации возможности перетаскивания элементов мышью.

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

    Потяните за край панели, чтобы изменить ее ширину:

    var lastX; // Отслеживает последнюю позицию X мыши var rect = document.querySelector("div"); rect.addEventListener("mousedown", function(event) { if (event.which == 1) { lastX = event.pageX; addEventListener("mousemove", moved); event.preventDefault(); // Предотвращает выделение } }); function buttonPressed(event) { if (event.buttons == null) return event.which != 0; else return event.buttons != 0; } function moved(event) { if (!buttonPressed(event)) { removeEventListener("mousemove", moved); } else { var dist = event.pageX - lastX; var newWidth = Math.max(10, rect.offsetWidth + dist); rect.style.width = newWidth + "px"; lastX = event.pageX; } }

    Обратите внимание, что обработчик «mousemove » зарегистрирован для всего окна. Даже если во время изменения размеров мышь выходит за пределы панели, мы все равно обновляем ширину панели и прекращаем JavaScript touch events , когда клавиша мыши была отпущена.

    Мы должны прекратить изменение размера панели, когда пользователь отпускает клавишу мыши. К сожалению, не все браузеры устанавливают для событий «mousemove » свойство which . Существует стандартное свойство buttons , которое предоставляет аналогичную информацию, но оно также поддерживается не во всех браузерах. К счастью, все основные браузеры поддерживают что-то одно: либо buttons , либо which . Функция buttonPressed в приведенном выше примере сначала пытается использовать свойство buttons , и, если оно не доступно, переходит к which .

    Когда курсор мыши наводится или покидает узел, запускаются события «mouseover » или «mouseout «. Они могут использоваться для создания эффектов при наведении курсора мыши, вывода какой-нибудь подписи или изменения стиля элемента.

    Чтобы создать такой эффект, недостаточно просто начать его отображение при возникновении события «mouseover » и завершить после события «mouseout «. Когда мышь перемещается от узла к одному из его дочерних элементов, для родительского узла происходит событие «mouseout «. Хотя указатель мыши не покинул диапазон распространения узла.

    Что еще хуже, эти JavaScript event распространяются так же, как и другие события. Когда мышь покидает один из дочерних узлов, для которого зарегистрирован обработчик, возникнет событие «mouseout «.

    Чтобы обойти эту проблему, можно использовать свойство объекта события relatedTarget . В случае возникновения события «mouseover » оно указывает, на какой элемент был наведен курсор мыши до этого. А в случае возникновения «mouseout » — к какому элементу перемещается указатель. Мы будем изменять эффект наведения мыши только, когда relatedTarget находится вне нашего целевого узла.

    В этом случае мы изменяем поведение, потому что курсор мыши был наведен на узел из-за его пределов (или наоборот ):

    Наведите курсор мыши на этот абзац.

    var para = document.querySelector("p"); function isInside(node, target) { for (; node != null; node = node.parentNode) if (node == target) return true; } para.addEventListener("mouseover", function(event) { if (!isInside(event.relatedTarget, para)) para.style.color = "red"; }); para.addEventListener("mouseout", function(event) { if (!isInside(event.relatedTarget, para)) para.style.color = ""; });

    Функция isInside отслеживает родительские связи заданного узла или пока не будет достигнута верхняя часть документа (когда node равен нулю ). Либо не будет найден родительский элемент, который нам нужен.

    Эффект наведения гораздо проще создать с помощью псевдоселектора CSS:hover , как показано в следующем примере. Но когда эффект наведения предполагает что-то более сложное, чем просто изменение стиля целевого узла, тогда нужно использовать прием с использованием событий «mouseover » и «mouseout » (JavaScript mouse events ):

    События прокрутки

    Каждый раз, когда элемент прокручивается, в нем срабатывает JavaScript scroll event . Его можно использовать для отслеживания того, что в данный момент просматривает пользователь; для отключения анимации, расположенной вне окна просмотра.

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

    .progress { border: 1px solid blue; width: 100px; position: fixed; top: 10px; right: 10px; } .progress > div { height: 12px; background: blue; width: 0%; } body { height: 2000px; }

    Scroll me...

    var bar = document.querySelector(".progress div"); addEventListener("scroll", function() { var max = document.body.scrollHeight - innerHeight; var percent = (pageYOffset / max) * 100; bar.style.width = percent + "%"; });

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

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

    Глобальная переменная innerHeight содержит высоту окна, которую мы должны вычесть из общей доступной прокручиваемой высоты документа. Нельзя прокручивать окно ниже при достижении нижней части документа. С innerHeight также может использоваться innerWidth . Разделив pageYOffset (текущую позицию окна прокрутки ) на максимально допустимую позицию прокрутки и умножив на 100, мы получаем процент для индикатора прогресса.

    Вызов preventDefault для JavaScript scroll event не предотвращает прокрутку. Обработчик события вызывается только после того, как происходит прокручивание.

    События фокуса ввода

    Когда элемент находится в фокусе ввода, браузер запускает в нем событие «focus «. Когда фокус ввода снимается, запускается событие «blur «.

    Эти два события не имеют распространения. Обработчик родительского элемента не уведомляется, когда дочерний элемент выделяется фокусом ввода.

    В следующем примере выводится подсказка для текстового поля, которое в данный момент находится в фокусе ввода:

    Имя:

    Возраст:

    var help = document.querySelector("#help"); var fields = document.querySelectorAll("input"); for (var i = 0; i < fields.length; i++) { fields[i].addEventListener("focus", function(event) { var text = event.target.getAttribute("data-help"); help.textContent = text; }); fields[i].addEventListener("blur", function(event) { help.textContent = ""; }); }

    Объект окна получает события «focus » и «blur «, когда пользователь переходит или покидает вкладку, окно браузера, в котором выводится документ.

    Событие загрузки

    Когда завершается загрузка страницы, для объектов тела документа и окна возникает JavaScript event «load» . Оно используется для планирования инициализации действий, для которых требуется загрузка всего документа. Не забывайте, что содержимое запускается сразу, когда встречается этот тег. Иногда это слишком рано. Например, когда скрипт должен сделать что-то с частями документа, которые загружаются после тега .

    и теги скриптов, которые загружают внешние файлы, также содержат событие «load «. Оно указывает, что файл, который был связан с ними, загружен. Как и события фокуса ввода, события загрузки не распространяются.

    Когда мы закрываем страницу или переходим на другую (например, нажав на ссылку ), срабатывает событие «beforeunload «. Оно применяется, чтобы предотвратить возможность случайной потери пользователем того, с чем он работал, после закрытия документа.

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

    Последовательность выполнения скриптов

    Запустить выполнение скрипта могут разные факторы: считывание тега, возникновение события. Метод requestAnimationFrame , задает вызов функции, перед тем как будет заново построена следующая страница. Это еще один способ, с помощью которого могут запускаться скрипты.

    События JavaScript select events и все остальные могут запускаться в любой момент, но в одном документе два скрипта никогда не запустятся одновременно. Если скрипт уже выполняется, обработчикам событий и фрагментам кода, запланированным другим скриптом, придется подождать своей очереди. Именно по этой причине документ замирает, когда скрипт работает в течение длительного времени. Браузер не реагирует на клики и другие события, поскольку не может запустить обработчики событий, пока текущий скрипт не закончит работу.

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

    Если нужно запустить процессы в фоновом режиме без замораживания страницы, браузеры предоставляют нам то, что называется web workers . Это изолированная среда JavaScript , которая работает с документом вместе с основной программой и может общаться с ним только путем отправки и получения сообщений.

    Предположим, что в файле с именем code/squareworker.js у нас есть следующий код:

    addEventListener("сообщение", function(event) { postMessage(event.data * event.data); });

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

    var squareWorker = new Worker("code/squareworker.js"); squareWorker.addEventListener("message", function(event) { console.log("The worker responded:", event.data); }); squareWorker.postMessage(10); squareWorker.postMessage(24);

    Функция postMessage отправляет сообщение, которое инициирует возникновение в приемнике события «message «. Скрипт, который создал web workers , отправляет и получает сообщения через объект Worker . С помощью этого объекта среда взаимодействуют с создавшим ее скриптом, посылая информацию и прослушивая его в своем глобальном с оригинальным скриптом.

    Установка таймеров

    Функция setTimeout похожа на requestAnimationFrame . Она задает вызов еще одной функции, которая будет вызываться позже. Но вместо того, чтобы вызывать функцию при следующем формировании страницы, она ждет определенное количество миллисекунд. В этом примере JavaScript event фон страницы из синего становится желтым через две секунды:

    document.body.style.background = "blue"; setTimeout(function() { document.body.style.background = "yellow"; }, 2000);

    Иногда нужно отменить функцию, которую мы запланировали. Это делается путем сохранения значения, возвращаемого функцией setTimeout , и вызова для нее clearTimeout :

    var bombTimer = setTimeout(function() { console.log("BOOM!"); }, 500); if (Math.random() < 0.5) { // 50% chance console.log("Defused."); clearTimeout(bombTimer); }

    Функция cancelAnimationFrame работает так же, как clearTimeout . Она вызывается значением, возвращаемым requestAnimationFrame , чтобы отменить кадр (если он еще не был вызван ).

    Похожий набор функций, setInterval и clearInterval используется для установки таймера, который должен повторять действие каждые X миллисекунд:

    var ticks = 0; var clock = setInterval(function() { console.log("tick", ticks++); if (ticks == 10) { clearInterval(clock); console.log("stop."); } }, 200);

    Дробление

    Некоторые типы событий могут запускаться много раз в течение короткого периода времени (например, «mousemove » и javascript scroll event ). При обработке таких событий, нужно быть осторожным, чтобы это не происходило очень долго, иначе обработчик будет выполнять действие столько времени, что взаимодействие с документом станет медленным и скачкообразным.

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

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

    Напечатайте что-нибудь здесь... var textarea = document.querySelector("textarea"); var timeout; textarea.addEventListener("keydown", function() { clearTimeout(timeout); timeout = setTimeout(function() { console.log("Вы перестали печатать."); }, 500); });

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

    Можно использовать иной сценарий, если нужно разделить ответы небольшим промежутком времени. Но чтобы при этом они запускались во время серии событий, а не только после нее. Например, можно отправлять в ответ на события «mousemove » (JavaScript mouse events ) текущие координаты мыши, но только через каждые 250 миллисекунд:

    function displayCoords(event) { document.body.textContent = "мышь находится в точке " + event.pageX + ", " + event.pageY; } var scheduled = false, lastEvent; addEventListener("mousemove", function(event) { lastEvent = event; if (!scheduled) { scheduled = true; setTimeout(function() { scheduled = false; displayCoords(lastEvent); }, 250); } });

    Заключение

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

    Каждое событие относится к определенному типу («keydown «, «focus » и так далее ), который идентифицирует его. Большинство событий вызывается для конкретного элемента DOM , а затем распространяются на родительские узлы элемента. Это позволяет обработчикам, связанным с этими элементами, обрабатывать их.

    Когда вызывается обработчик, ему передается объект события с дополнительной информацией о действии. Этот объект также содержит методы, позволяющие остановить дальнейшее распространение события (stopPropagation ) или предотвратить обработку события браузером по умолчанию (preventDefault ).

    Нажатие клавиш порождает события «keydown «, «keypress » и «keyup «. Нажатие мыши порождает события «mousedown «, «mouseup » и «click «. Перемещение мыши — «mousemove «, «mouseenter » и «mouseout «.

    JavaScript scroll event можно определить с помощью события «scroll «, а смена фокуса — «focus » и «blur «. После завершения загрузки документа для окна возникает событие «load «.

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

    Данная публикация представляет собой перевод статьи «Handling Events » , подготовленной дружной командой проекта

    Вверх