Источник: http://learn.javascript.ru/introduction-browser-events
Для реакции на действия посетителя и внутреннего взаимодействия скриптов существуют события.
Событие – это сигнал от браузера о том, что что-то произошло.
Существует много видов событий.
click происходит, когда кликнули на элемент;mouseover — когда на элемент наводится мышь;focus — когда посетитель фокусируется на элементе;keydown — когда посетитель нажимает клавишу.resize — когда изменяется размер окна.load, readystatechange, DOMContentLoaded…События соединяют JavaScript-код с документом и посетителем, позволяя создавать динамические интерфейсы.
Есть несколько способов назначить событию обработчик. Сейчас мы их рассмотрим, начиная от самого простого.
Обработчик может быть назначен прямо в разметке, в атрибуте, который называется on<событие>.
Например, чтобы прикрепить click-событие к input-кнопке, можно присвоить обработчик onclick, вот так:
<input id="b1" value="Нажми меня" onclick="alert('Спасибо!')" type="button"/>
При клике мышкой на кнопке выполнится код, указанный в атрибуте onclick.
В действии:
Обратите внимание, внутри alert используются одиночные кавычки, так как сам атрибут находится в двойных.
Запись вида onclick="alert("Клик")" не будет работать. Если вам действительно нужно использовать именно двойные кавычки, то это можно сделать, заменив их на &quot;: onclick="alert(&quot;Клик&quot;)".
Однако, обычно этого не требуется, так как в разметке пишутся только очень простые обработчики. Если нужно сделать что-то сложное, то имеет смысл описать это в функции, и в обработчике вызвать её.
Следующий пример по клику запускает функцию countRabbits().
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<script>
function countRabbits() {
for(var i = 1; i <= 3; i++) {
alert("Кролик номер " + i);
}
}
</script>
</head>
<body>
<input type="button" onclick="countRabbits()" value="Считать кроликов!"/>
</body>
</html>
Как мы помним, атрибут HTML-тега не чувствителен к регистру, поэтому ONCLICK будет работать так же, как onClick или onclick… Но, как правило, атрибуты пишут в нижнем регистре: onclick.
Можно назначать обработчик, используя свойство DOM-элемента on<событие>.
Пример установки обработчика click элементу с id="myElement":
<input id="myElement" type="button" value="Нажми меня"/>
<script>
var elem = document.getElementById('myElement');
elem.onclick = function() {
alert('Спасибо');
}
</script>
В действии:
Если обработчик задан через атрибут, то соответствующее свойство появится у элемента автоматически. Браузер читает HTML-разметку, создаёт новую функцию из содержимого атрибута и записывает в свойство onclick.
Первичным является именно свойство, а атрибут — лишь способ его инициализации.
Эти два примера кода работают одинаково:
<input type="button" onclick="alert('Клик!')" value="Кнопка"/>
<input type="button" id="button" value="Кнопка"/>
<script>
document.getElementById('button').onclick = function() {
alert('Клик!');
}
</script>
Так как свойство, в итоге, одно, то назначить по обработчику и там и там нельзя.
В примере ниже, назначение через JavaScript перезапишет обработчик из атрибута:
<input type="button" onclick="alert('До')" value="Нажми меня"/>
<script>
var elem = document.getElementsByTagName('input')[0];
elem.onclick = function() { // перезапишет существующий обработчик
alert('После');
}
</script>
Обработчиком можно назначить уже существующую функцию:
function sayThanks() {
alert('Спасибо!');
}
document.getElementById('button').onclick = sayThanks;
sayThanks, а не sayThanks():document.getElementById('button').onclick = sayThanks;
Если добавить скобки, то sayThanks() — будет уже результат выполнения функции (а так как в ней нет return, то в onclick попадёт undefined). Нам же нужна именно функция.
А вот в разметке как раз скобки нужны:
<input type="button" id="button" onclick="sayThanks()"/>
Это различие просто объяснить. При создании обработчика браузером по разметке, он автоматически создает функцию из его содержимого. Поэтому последний пример – фактически то же самое, что:
document.getElementById('button').onclick = function() {
sayThanks(); // содержимое атрибута
}
elem.setAttribute('onclick', func).Хотя, с другой стороны, если func — строка, то такое присвоение будет успешным, например:
// сработает, будет при клике выдавать 1
document.body.setAttribute('onclick', 'alert(1)');
Браузер в этом случае сделает функцию-обработчик с телом из строки alert(1).
…А вот если func — не строка, а функция (как и должно быть), то работать совсем не будет:
// при нажатии на body будут ошибки
document.body.setAttribute('onclick', function() { alert(1) });
Значением атрибута может быть только строка. Любое другое значение преобразуется в строку. Функция в строчном виде обычно даёт свой код: "function() { alert(1) }".
Запись elem.onclick = 'alert(1)' будет работать, но не рекомендуется.
При использовании в такой функции-строке переменных из замыкания будут проблемы с JavaScript-минификаторами. Здесь мы не будем вдаваться в детали этих проблем, но общий принцип такой — функция должна быть function.
on<событие> должно быть написано в нижнем регистре.Свойство ONCLICK работать не будет.
Внутри обработчика события this ссылается на текущий элемент. Это можно использовать, чтобы получить свойства или изменить элемент.
В коде ниже button выводит свое содержимое, используя this.innerHTML:
<button onclick="alert(this.innerHTML)">Нажми меня</button>
В действии:
Фундаментальный недостаток описанных способов назначения обработчика — невозможность повесить несколько обработчиков на одно событие.
Например, одна часть кода хочет при клике на кнопку делать ее подсвеченной, а другая — выдавать сообщение. Нужно в разных местах два обработчика повесить.
При этом новый обработчик будет затирать предыдущий. Например, следующий код на самом деле назначает один обработчик — последний:
input.onclick = function() { alert(1); }
// ...
input.onclick = function() { alert(2); } // заменит предыдущий обработчик
Конечно, это можно обойти разными способами, в том числе написанием фреймворка вокруг обработчиков. Но существует и другой метод назначения обработчиков, который свободен от указанного недостатка.
Для назначения обработчиков существуют специальные методы. Как правило, в браузерах они стандартные, кроме IE<9, где они похожи, но немного другие.
Сначала посмотрим метод для старых IE, т.к. оно чуть проще.
Назначение обработчика осуществляется вызовом attachEvent:
element.attachEvent( "on"+event, handler);
Удаление обработчика — вызовом detachEvent:
element.detachEvent( "on"+event, handler);
Например:
var input = document.getElementById('button')
function handler() {
alert('спасибо!')
}
input.attachEvent( "onclick" , handler) // Назначение обработчика
// ....
input.detachEvent( "onclick", handler) // Удаление обработчика
Обычно, обработчики ставятся. Но бывают ситуации, когда их нужно удалять или менять.
В этом случае нужно передать в метод удаления именно функцию-обработчик. Такой вызов будет неправильным:
input.attachEvent( "onclick" ,
function() {alert('Спасибо!')}
)
// ....
input.detachEvent( "onclick",
function() {alert('Спасибо!')}
)
Несмотря на то, что функции работают одинаково, это две разных функции.
Использование attachEvent позволяет добавлять несколько обработчиков на одно событие одного элемента.
Пример ниже будет работать только в IE и Opera:
<input id="myElement" type="button" value="Нажми меня"/>
<script>
var myElement = document.getElementById("myElement")
var handler = function() {
alert('Спасибо!')
}
var handler2 = function() {
alert('Спасибо еще раз!')
}
myElement.attachEvent("onclick", handler); // первый
myElement.attachEvent("onclick", handler2); // второй
</script>
У обработчиков, назначенных с attachEvent, нет this.
Это важная особенность и подводный камень старых IE.
Официальный способ назначения обработчиков из стандарта W3C работает во всех современных браузерах, включая IE9+.
Назначение обработчика:
element.addEventListener(event, handler, phase);
Удаление:
element.removeEventListener(event, handler, phase);
Как видите, похоже на attachEvent/detachEvent, только название события пишется без префикса «on».
Еще одно отличие от синтаксиса Microsoft — это третий параметр: phase, который обычно не используется и выставлен в false. Позже мы посмотрим, что он означает.
Использование этого метода — такое же, как и у attachEvent:
function handler() { ... }
elem.addEventListener( "click" , handler, false) // назначение обработчика
elem.removeEventListener( "click", handler, false) // удаление обработчика
Можно объединить способы для IE<9 и современных браузеров, создав свои методы addEvent(elem, type, handler) и removeEvent(elem, type, handler):
var addEvent, removeEvent;
if (document.addEventListener) { // проверка существования метода
addEvent = function(elem, type, handler) {
elem.addEventListener(type, handler, false);
};
removeEvent = function(elem, type, handler) {
elem.removeEventListener(type, handler, false);
};
} else {
addEvent = function(elem, type, handler) {
elem.attachEvent("on" + type, handler);
};
removeEvent = function(elem, type, handler) {
elem.detachEvent("on" + type, handler);
};
}
...
// использование:
addEvent(elem, "click", function() { alert("Привет"); });
Это хорошо работает в большинстве случаев, но у обработчика не будет this в IE, потому что attachEvent не поддерживает this.
Кроме того, в IE<8 есть проблемы с утечками памяти… Но если вам не нужно this, и вы не боитесь утечек (как вариант — не поддерживаете IE<8), то это решение может подойти.
Есть три способа назначения обработчиков событий:
onclick="...".elem.onclick = function.elem.attachEvent(on+событие, handler) (удаление через detachEvent).elem.addEventListener(событие, handler, false) (удаление через removeEventListener).Все способы, кроме attachEvent, обеспечивают доступ к элементу, на котором сработал обработчик, через this.