Введение в браузерные события

Событие – это сигнал от браузера о том, что что-то произошло.

Список самых часто используемых событий

События мыши:

  • click – происходит, когда кликнули на элемент левой кнопкой мыши
  • contextmenu – происходит, когда кликнули на элемент правой кнопкой мыши
  • mouseover – возникает, когда на элемент наводится мышь
  • mouseout возникает, когда ушла мышь
  • mousedown и mouseup – когда кнопку мыши нажали или отжали
  • mousemove – при движении мыши

Свойства объекта события

<input type="button" value="Нажми меня" id="elem">

<script>
  elem.onclick = function(event) {
    // вывести тип события, элемент и координаты клика
    alert(event.type + " на " + event.currentTarget);
    alert(event.clientX + ":" + event.clientY);
  }
</script>

event.type - Тип события, в данном случае click

event.target - Элемент, на котором произошел click

event.relatedTarget - Элемент с которого пришли

event.currentTarget - Элемент, на котором сработал обработчик. Значение – в точности такое же, как и у this, но бывают ситуации, когда обработчик является методом объекта и его this при помощи bind привязан к этому объекту, тогда мы можем использовать event.currentTarget.

event.clientX / event.clientY - Координаты курсора в момент клика (относительно окна)

event.keyCode - код нажатой кнопкию

Полное описание: Event Object

События на элементах управления:

  • submit – посетитель отправил форму <form>
  • focus – посетитель фокусируется на элементе, например нажимает на <input>
  • blur –  посетитель уводят фокус с  элемента <input>
  • change – посетитель сделал изменения в элементе, например в <textarea>

Клавиатурные события:

  • keydown – когда посетитель нажимает клавишу
  • keyup – когда посетитель отпускает клавишу
  • keypress - когда посетитель нажал клавишу

Cross Browser Key Table

События CSS:

  • transitionend – когда CSS-анимация завершена.

События документа:

  • DOMContentLoaded – когда HTML загружен и обработан, DOM документа полностью построен и доступен.

Если после стиля идёт скрипт, то этот скрипт обязан дождаться, пока стиль загрузится:

<link type="text/css" rel="stylesheet" href="style.css">
<script>
  // сработает после загрузки style.css
</script>
  1. Побочный эффект – так как событие DOMContentLoaded будет ждать выполнения скрипта, то оно подождёт и загрузки стилей, которые идут перед <script>.

  2. АвтозаполнениеЭто означает, что если на странице есть форма для ввода логина-пароля, то браузер введёт в неё запомненные значения только по DOMContentLoaded.

События документа load

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

Когда человек уходит со страницы или закрывает окно, на window срабатывает событие unload. В нём можно сделать что-то, не требующее ожидания, например, закрыть вспомогательные popup-окна, но отменить сам переход нельзя.

События документа beforeunload 

События документа unload

Если посетитель инициировал переход на другую страницу или нажал «закрыть окно», то обработчик onbeforeunload может приостановить процесс и спросить подтверждение.

Также есть и много других событий:

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

Использование атрибута HTML

<input type="button" onclick="alert('Клик!')" value="Кнопка"/>
<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <script>
    function sayClick() {
      alert('Клик!');
    }
  </script>
</head>
<body>
  <input type="button" onclick="sayClick()" value="Кнопка"/>
</body>
</html>

Использование свойства DOM-объекта

<input id="elem" type="button" value="Нажми меня" />
<script>
  elem.onclick = function() {
    alert( 'Спасибо' );
  };
</script>
function sayThanks() {
  alert( 'Спасибо!' );
}

elem.onclick = sayThanks;


elem.onclick = sayThanks();
function sayThanks() {
  alert( 'Спасибо!' );
}

<input type="button" id="button" onclick="sayThanks()" />

button.onclick = function() {
  sayThanks(); // содержимое атрибута
};

addEventListener и removeEventListener

elem.addEventListener(event, handler[, phase]);

event - Имя события, например click

handlerСсылка на функцию, которую надо поставить обработчиком.

phase - Необязательный аргумент, «фаза», на которой обработчик должен сработать.

function handler() {
  alert( 'Спасибо!' );
}

elem.addEventListener("click", handler);
// ....
elem.removeEventListener("click", handler);

Примеры

<input id="elem" type="button" value="Нажми меня"/>

<script>
  function handler1() {
    alert('Спасибо!');
  };

  function handler2() {
    alert('Спасибо ещё раз!');
  }

  elem.onclick = function() { alert("Привет"); };
  elem.addEventListener("click", handler1); // Спасибо!
  elem.addEventListener("click", handler2); // Спасибо ещё раз!
</script>
function handler() {
  alert( 'Спасибо!' );
}
button.attachEvent("onclick", handler) // Назначение обработчика
// ....
button.detachEvent("onclick", handler) // Удаление обработчика

Отличия IE8-

У обработчиков, назначенных с attachEvent, нет this

<meta charset="utf-8">
<style>
  button {
    transition: width 1s;
    width: 100px;
  }
  .wide { width: 300px; }
</style>

<button id="elem" onclick="this.classList.toggle('wide');">Нажми меня</button>

<script>
  // addEventListener работает всегда, а DOM-свойство – нет
  elem.ontransitionend = function() {
    alert( "ontransitionend" ); // не сработает
  };

  elem.addEventListener("transitionend", function() {
    alert( "addEventListener" ); // сработает по окончании анимации
  });
</script>

Разница

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

Порядок обработки событий

<textarea rows="8" cols="40" id="area">Кликни меня</textarea>

<script>
  area.onmousedown = function() { this.value += "mousedown\n"; this.scrollTop = this.scrollHeight; };
  area.onmouseup = function() { this.value += "mouseup\n"; this.scrollTop = this.scrollHeight; };
  area.onclick = function() { this.value += "click\n"; this.scrollTop = this.scrollHeight; };
</script>

Таким образом, при нажатии кнопки мыши в очередь попадёт событие mousedown, а при отпускании – сразу два события: mouseup и click. Браузер обработает их строго одно за другим: mousedown →mouseup → click.

Очередь событий

<input type="button" id="button" value="Нажми меня">
<input type="text" id="text" size="60">

<script>
  button.onclick = function() {
    text.value += ' ->в onclick ';

    text.focus(); // вызов инициирует событие onfocus

    text.value += ' из onclick-> ';
  };

  text.onfocus = function() {
    text.value += ' !focus! ';
  };
</script>

Вложенные (синхронные) события

<input type="button" id="button" value="Нажми меня">
<input type="text" id="text" size="60">

<script>
  button.onclick = function() {
    text.value += ' ->в onclick ';

    setTimeout(function() {
      text.focus(); // сработает после onclick
    }, 0);

    text.value += ' из onclick-> ';
  };

  text.onfocus = function() {
    text.value += ' !focus! ';
  };
</script>

Вложенные (асинхронные) события

Всплытие и перехват

Всплытие

<style>
  body * {
    margin: 10px;
    border: 1px solid blue;
  }
</style>

<form onclick="alert('form')">FORM
  <div onclick="alert('div')">DIV
    <p onclick="alert('p')">P</p>
  </div>
</form>

Отличия  this от event.currentTarget

var form = document.querySelector('form');

form.onclick = function(event) {
  event.target.style.backgroundColor = 'yellow';

  alert("target = " + event.target.tagName + ", this=" + this.tagName);

  event.target.style.backgroundColor = '';
};
  • event.target – это исходный элемент, на котором произошло событие, в процессе всплытия он неизменен.
  • this, event.currentTarget – это элемент, до которого дошло всплытие и на котором выполняется обработчик.
  • this - Может быть переопределен.

Прекращение всплытия

<style>
  body * {
    margin: 10px;
    border: 1px solid blue;
  }
</style>

<form onclick="alert('form')">FORM
  <div onclick="alert('div')">DIV
    <p id="paragraph" onclick="event.stopPropagation()">P</p>
  </div>
</form>

event.stopImmediatePropagation()

<style>
  body * {
    margin: 10px;
    border: 1px solid blue;
  }
</style>

<form onclick="alert('form')">FORM
  <div onclick="alert('div')">DIV
    <p id="paragraph">P</p>
  </div>
</form>

<script>
    paragraph.addEventListener('mousedown', function (e) {alert(1);});
    paragraph.addEventListener('mousedown', function (e) {
        // (1) Ппредотвращает всплытие!
        // (2) Останавливает обработку событий на текущем элементе. (+)
        e.stopImmediatePropagation(); // 
        alert(2);
    });
    paragraph.addEventListener('mousedown', function (e) {alert(3);});
</script>

Не прекращайте всплытие без необходимости!

  • Мы делаем меню. Оно обрабатывает клики на своих элементах и делает для них stopPropagation. Вроде бы, всё работает.

 

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

 

  • Над областью, где клики убиваются stopPropagation, статистика работать не будет! Получилась «мёртвая зона».

standart DOM Events 3

var elems = document.querySelectorAll('form,div,p');

for (var i = 0; i < elems.length; i++) {
  elems[i].addEventListener("click", highlightThis, true);
  elems[i].addEventListener("click", highlightThis, false);
}

function highlightThis() {
  this.style.backgroundColor = 'yellow';
  alert(this.tagName);
  this.style.backgroundColor = '';
}

Полный пример по ссылке:

http://plnkr.co/edit/PCgDQbLvSZsFkbTPvyWd?p=preview

Отличия IE8-

  1. event.currentTarget - Нет свойства. Если нужен, можно будет взять лишь из замыкания.
  2. ​​​Вместо event.target в IE8- используется event.srcElement
elem.onclick = function(event) {
  event = event || window.event;
  var target = event.target || event.srcElement;

  // ... теперь у нас есть объект события и target
  ...
}
event.stopPropagation ? event.stopPropagation() : (event.cancelBubble=true);

Для остановки всплытия используется код event.cancelBubble=true.

Делегирование событий

Пример

ul.onclick = function(event) {
  var target = event.target;

  // цикл двигается вверх от target к родителям до ul
  while (target != this) {
    if (target.tagName == 'LI') {
      // нашли элемент, который нас интересует!
      fn(target);
      return;
    }
    target = target.parentNode;
  }
}

Приём проектирования "поведение"

Счётчик: <button data-counter>1</button>
Ещё счётчик: <button data-counter>2</button>

<script>
    document.onclick = function (event) {
        if (event.target.hasAttribute('data-counter')) {
            event.target.innerHTML++;
        }
    };
</script>
<button data-toggle-id="subscribe-mail">
  Показать форму подписки
</button>

<form id="subscribe-mail" hidden>
  Ваша почта: <input type="email">
</form>

<script>
  document.onclick = function(event) {
    var target = event.target;

    var id = target.getAttribute('data-toggle-id');
    if (!id) return;

    var elem = document.getElementById(id);

    elem.hidden = !elem.hidden;
  };
</script>

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

  • Экономит память: не нужно вешать много обработчиков.
  • Меньше кода: не нужно ставить или снимать обработчики.
  • Удобство изменений: можно массово добавлять или удалять элементы путём изменения innerHTML.

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

  • Клик по ссылке инициирует переход на новый URL.
  • Нажатие на кнопку «отправить» в форме – отсылку ее на сервер.
  • Двойной клик на тексте – инициирует его выделение.
  • Клик по checkbox
  • wheel - движение колёсика мыши инициирует прокрутку.

Например

Отмена действия браузера

<a href="/" onclick="return false">Нажми здесь</a>
<a href="/" onclick="event.preventDefault()">здесь</a>

Особенности IE8-

event.preventDefault ? event.preventDefault() : (event.returnValue=false);

Генерация событий на элементах

API / DOM 3 Events.

eventInterface – это тип события, например MouseEventFocusEventKeyboardEvent.

var event = document.createEvent(eventInterface);

Аргументы:

  • type – тип события, например "click".
  • bubbles – всплывает ли событие.
  • cancelable – можно ли отменить событие.
var event = document.createEvent("Event");
event.initEvent("hello", true, true);
elem.dispatchEvent(event)

API / DOM 3 Events.

<h1 id="elem">Привет от скрипта!</h1>

<script>
document.addEventListener("hello", function(event) {
    alert( "Привет" );
    event.preventDefault();
}, false);

var event = document.createEvent("Event");
event.initEvent("hello", true, true);

if (elem.dispatchEvent(event) === false) {
    alert( 'Событие было отменено preventDefault' );
}
</script>

API / DOM 3 Events.

<h1 id="elem">Привет от скрипта!</h1>

<script>
document.addEventListener("hello", function(event) {
    alert( "Привет" );
    event.preventDefault();
}, false);

var event = document.createEvent("Event");
event.initEvent("hello", true, true);

if (elem.dispatchEvent(event) === false) {
    alert( 'Событие было отменено preventDefault' );
}
</script>

The end!

RD Events

By Sarhan Azizov

RD Events

  • 440