JavaScript - Всплытие события. Продвинутая работа с объектом Event на JavaScript Всплытие событий javascript

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

Всплытие события

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

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

Всплытие события (пузырька) продемонстрируем на следующем примере:

Заголовок

Некоторый очень важный текст

Раздел

Некоторый текст

Остальной текст

Напишем небольшой скрипт, с помощью которого добавим обработчик события " click " для всех элементов страницы, а также для объектов document и window .

document.addEventListener("DOMContentLoaded", function() { var allElements = document.getElementsByTagName("*"); for (var i=0; i < allElements.length; i++) { allElements[i].addEventListener("click",function() {console.log(this.tagName);},false); }; document.addEventListener("click",function() {console.log(this);},false); window.addEventListener("click",function() {console.log(this);},false); });

Создадим HTML-страницу и вставим в неё вышеприведённый HTML код. Сценарий, написанный на языке JavaScript, вставим перед закрывающим тегом body . После этого откроем только что созданную страницу в веб-браузере, нажмём клавишу F12 и перейдём в консоль. Теперь нажмём левой кнопкой мышкой в области, принадлежащей элементу strong , и посмотрим, как событие будет всплывать.

Как прервать всплытие события

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

Например, изменим наш вышеприведённый пример таким образом, чтобы событие не всплывало выше body: document.addEventListener("DOMContentLoaded", function() { var allElements = document.getElementsByTagName("*"); for (var i=0; i

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

Получение элемента, который вызвал обработчик

Для того чтобы получить DOM-элемент (объект), который вызвал обработчик события, необходимо использовать ключевое слово this . Данное ключевое слово (this) доступно в обработчике только в том случае, если Вы подписались на событие с помощью JavaScript.

Например, выведем в консоль id элемента, который вызвал обработчик события:

Var myP = document.getElementById("myP"); myP.addEventListener("click",function(){ //получим DOM-элемент, который вызвал обработчик события - this //получим его id и выведем его в консоль console.log(this.id); });

Для получения текущего элемента также можно использовать свойство currentTarget (event.currentTarget).

Этапы (фазы) прохода события

Перед тем как события начинает всплывать (этап всплытия), оно предварительно проходит ещё 2 этапа:

  • 1 этап - это этап погружения до элемента, сгенерировавшего событие. Т.е. на данном этапе происходит движение сверху вниз, т.е. от объекта window до элемента. Также данный этап ещё называют этапом перехвата.
  • 2 этап - это этап достижение цели, т.е. элемента (объекта), сгенерировавшего событие.

С учётом всех этапов, которые проходит событие, получается следующая картина:

Изменим сценарий вышеприведённого примера следующим образом:

Document.addEventListener("DOMContentLoaded", function() { var allElements = document.getElementsByTagName("*"); for (var i=0; i

Третий параметр методов addEventListener и removeEventListener определяет этап, на котором будет поймано событие. Если данный параметр имеет значение true , то событие будет перехватываться на стадии погружения (перехвата) события. А если параметр имеет значение false , то событие будет перехватываться на этапе всплытия. Для обработки события на самой цели, можно использовать метод addEventListener как со значением false , так и со значением true .

Внимание: на стадии погружения (перехвата), события могут перехватывать только обработчики, добавленные с помощью метода addEventListener() . Обработчики, добавленные с помощью других способов (атрибута HTML или через JavaScript с помощью свойства on[событие]) могут перехватывать события только на стадии всплытия.

Получение элемента, который сгенерировал событие

Для того чтобы получить целевой элемент, т.е. элемент, который сгенерировал событие, необходимо использовать свойство target (event.target).

Рассмотрим вышеприведённый пример, в котором изменим содержимое элемента script на следующее:

Document.addEventListener("DOMContentLoaded", function() { var elementBody = document.body; elementBody.addEventListener("click",function(){ console.log(this.tagName + " - элемент, который вызвал обработчик"); console.log(event.currentTarget.tagName + " - элемент, который вызвал обработчик"); console.log(event.target.tagName + " - элемент, который сгенерировал событие"); },false); });

Продемонстрируем наш пример, кликнув левой кнопкой мыши в области, принадлежащей элементу strong:

Сейчас мы с вами разберем некоторые продвинутые вещи при работе с объектом Event, а именно: всплытие и перехват, а также делегирование событий.

Всплытие событий

Представьте себе, что у вас есть несколько вложенных друг в друга блоков:

самый внутренний блок

Когда вы кликаете на самый внутренний блок, событие onclick возникает сначала в нем, а затем срабатывает в его родителе, в родителе его родителя и так далее, пока не дойдет то тега body и далее до тега html (затем до document и до window ).

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

Давайте убедимся в этом на следующем примере: у нас есть 3 блока, к каждому из них привязано событие onclick:

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

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

event.target

Пусть у нас есть два элемента: div и абзац p, лежащий внутри этого дива. Пусть onlick мы привязали в диву:

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

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

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

Однако, иногда нам хотелось бы знать - клик произошел непосредственно по диву или по его потомку абзацу. В этом нам поможет объект Event и его свойство event.target - в нем хранится именно тот элемент, в котором произошел клик.

В следующем примере у нас есть div , внутри него лежит p , а внутри него - span .

Давайте привяжем событие onclick самому верхнему элементу (диву) и будем кликать на разные элементы: на div, на p, на span. С помощью event.target получим самый нижний элемент, в котором случилось событие и выведем его название с помощью tagName .

Если кликнуть, к примеру, на span - то событие отловит наш div (ведь именно к нему привязан onclick), но в event.target будет лежать именно span :

Покликайте по разным блокам - вы увидите результат:

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

Итак, вы уже знаете, что все события всплывают до самого верха (до тега html, а затем до document, а затем до window). Иногда есть нужда это всплытие остановить. Это может сделать любой элемент, через который всплывает событие. Для этого в коде элемента следует вызвать метод event.stopPropagation() .

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

Кликните на красный блок - вы увидите результат:

Погружение

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

Повесить обработчик события с учетом стадии перехвата можно только с помощью addEventListener . Для этого у него есть третий параметр: если он равен true - событие сработает на стадии перехвата, а если false - на стадии всплытия (это по умолчанию):

Var green = document.getElementById("green"); green.addEventListener("click", func, true); function func(event) { }

Стадию, на которой произошло событие можно определить с помощью свойства event.eventPhase . Оно может принимать следующие значения: 1 - стадия перехвата, 2 - стадия цели, 3 - стадия всплытия.

Вступление к делегированию

Представим себе ситуацию: пусть у нас есть ul с несколькими li . К каждой li привязано следующее событие: по нажатию на li ей в конец добавляется "!".

Давайте реализуем описанное:

  • пункт 1
  • пункт 2
  • пункт 3
  • пункт 4
  • пункт 5
var li = document.querySelectorAll("#ul li"); //В цикле вешаем функцию addSign на каждую li: for (var i = 0; i

Понажимайте на li - вы увидите, как им в конец добавляется "!":

  • пункт 1
  • пункт 2
  • пункт 3
  • пункт 4
  • пункт 5

Пусть теперь у нас также есть кнопочка, по нажатию на которую в конец ul добавляется новая li с текстом "пункт". Нас ждет сюрприз: привязанное событие не будет работать для новых li! Убедимся в этом:

  • пункт 1
  • пункт 2
  • пункт 3
  • пункт 4
  • пункт 5
Добавить li

Нажмите на кнопочку для добавления li, а затем на эту новую li - она не среагирует:

  • пункт 1
  • пункт 2
  • пункт 3
  • пункт 4
  • пункт 5
Добавить li

Для решения проблемы можно в момент создания новой li повесить на нее функцию addSign через addEventListener. Давайте реализуем это:

  • пункт 1
  • пункт 2
  • пункт 3
  • пункт 4
  • пункт 5
Добавить li var li = document.querySelectorAll("#ul li"); for (var i = 0; i

  • пункт 1
  • пункт 2
  • пункт 3
  • пункт 4
  • пункт 5
Добавить li

Существует и второй способ обойти проблему - делегирование событий. Давайте его разберем.

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

Суть делегирования в следующем: навесим событие не на каждую li, а на их родителя - на ul .

При этом работоспособность нашего скрипта должна сохраниться: по-прежнему при клике на li ей в конец будет добавляться "!". Только событие в новом варианте будет навешано на ul:

Var ul = document.getElementById("ul"); //Вешаем событие на ul: ul.addEventListener("click", addSign); function addSign() { }

Как мы это провернем: так как событие навешано на ul, то внутри функции мы можем поймать li с помощью event.target . Напомню, что такое event.target - это именно тот тег, в котором случился клик, в нашем случае это li .

Итак, вот решение нашей задачи через делегирование:

  • пункт 1
  • пункт 2
  • пункт 3
  • пункт 4
  • пункт 5

Результат выполнения кода:

  • пункт 1
  • пункт 2
  • пункт 3
  • пункт 4
  • пункт 5

При этом наше решение будет работать автоматически даже для новых li , ведь событие навешено не на li, а на ul:

  • пункт 1
  • пункт 2
  • пункт 3
  • пункт 4
  • пункт 5
Добавить li var ul = document.getElementById("ul"); ul.addEventListener("click", addSign); function addSign() { event.target.innerHTML = event.target.innerHTML + "!"; } //Реализация кнопочки добавления новой li: var button = document.getElementById("button"); button.addEventListener("click", addLi); function addLi() { var li = document.createElement("li"); li.innerHTML = "новая li"; ul.appendChild(li); }

Нажмите на кнопочку для добавления li, а затем на эту новую li - она среагирует:

  • пункт 1
  • пункт 2
  • пункт 3
  • пункт 4
  • пункт 5
Добавить li

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

Универсальное делегирование событий

Недостаток нашего кода проявится в том случае, когда внутри li будут какие-то вложенные теги. В нашем случае пусть это будут теги i :

В этом случае нажатие на i приведет к добавлению восклицательного знака в конец тега i , а не тега li , как мы хотели бы (если нажать на li вне курсива - то все будет ок):

  • пункт курсив 1
  • пункт курсив 2
  • пункт курсив 3
  • пункт курсив 4
  • пункт курсив 5
var ul = document.getElementById("ul"); ul.addEventListener("click", addSign); function addSign() { event.target.innerHTML = event.target.innerHTML + "!"; }

Нажмите на курсив - вы увидите как "!" добавится ему в конец (нажатие вне курсива будет работать нормально):

Проблема исправляется следующим образом (описанный способ не единственный, но самый простой): с помощью метода closest найдем ближайшую li, котоорая является родителем для event.target вот так: event.target.closest("li") .

Как это работает: если клик был на i , то в event.target лежит этот i, а в event.target.closest("li") - наша li, для которой должно сработать событие.

Если же клик был на самой li , то и в event.target , и в event.target.closest("li") будет лежать наша li.

Давайте проверим:

  • пункт курсив 1
  • пункт курсив 2
  • пункт курсив 3
  • пункт курсив 4
  • пункт курсив 5
var ul = document.getElementById("ul"); ul.addEventListener("click", function(event) { var li = event.target.closest("li"); if (li) { //проверяем, вдруг li-родителя вообще нет li.innerHTML = li.innerHTML + "!"; } });

Результат выполнения кода:

Не важно, какая глубина вложенности: тег i может лежать в теге b , а тот в теге span и только потом в li - это не имеет значения: конструкция event.target.closest("li") найдет родителя из любого уровня вложенности.

Перехват события

Одна из важных особенностей языка - перехват события. Если кто-то, к примеру, щелкает на кнопке, то вызывается программа обработки события onClick, соответствующая этой кнопке. С помощью обработки событий Вы можете добиться того, чтобы объект, соответсвующий вашему окну, документу или слою, перехватывал и обрабатывал событие еще до того, как для этой цели объектом указанной кнопки будет вызван обработчик событий. Точно так же объект вашего окна, документа или слоя может обрабатывать сигнал о событии еще до того, как он достигает своего обычного адресата.
Чтобы увидеть, для чего это может пригодиться, давайте рассмотрим следующий пример:



window.onclick= handle;

function handle(e) {­
alert("Объект window перехватывает это событие!");
return true; // т.е. проследить ссылку
}




Click on this link

Как видно, мы не указываем программы обработки событий в тэге . Вместо этого мы пишем

window.captureEvents(Event.CLICK);

с тем, чтобы перехватить событие Click объектом window. Обычно объект window не работает с событием Click . Однако, перехватив, мы затем его переадресуем в объект window. Заметим, что в Event.CLICK фрагмент CLICK должен писаться заглавными буквами. Если же Вы хотите перехватывать несколько событий, то Вам следует отделить их друг от друга символами |. Например:

window.captureEvents(Event.CLICK | Event.MOVE);

Помимо этого в функции handle() , назначенной нами на роль обработчика событий, мы пользуемся инструкцией return true; . В действительности это означает, что браузер должен обработать и саму ссылку, после того, как завершится выполнение функции handle() . Если же Вы напишете вместо этого return false; , то на этом все и закончится.

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

function handle(e) {­
alert("The window object captured this event!");
window.routeEvent(e);
return true;
}

то компьютер будет проверять, определены ли другие программы обработки событий для данного объекта. Переменная e - это наш объект Event, передаваемый функции обработки событий в виде аргумента.

Кроме того, Вы можете непосредственно послать сигнал о событии какому-либо объекту. Для этого Вы можете воспользоваться методом handleEvent() . Это выглядит следующим образом:


window.captureEvents(Event.CLICK);

window.onclick= handle;

function handle(e) {­
document.links.handleEvent(e);
}


"Кликните" по этой ссылке

Вторая ссылка

Все сигналы о событиях Click, посылаются на обработку по второй ссылке - даже если Вы вовсе и не щелкнули ни по одной из ссылок!

Следующий скрипт демонстрирует, как Ваш скрипт может реагировать на сигналы о нажатии клавиш. Нажмите на какую-либо клавишу и посмотрите, как работает этот скрипт.


window.captureEvents(Event.KEYPRESS);

window.onkeypress= pressed;

function pressed(e) {­
alert("Key pressed! ASCII-value: " + e.which);
}

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

Например, есть 3 вложенных элемента FORM > DIV > P , с обработчиком на каждом:

Код: FORM
DIV

Всплытие гарантирует, что клик по внутреннему

Вызовет обработчик onclick (если есть) сначала на самом

Поэтому если в примере выше кликнуть на P, то последовательно выведутся alert: p → div → form.

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

event.target

На каком бы элементе мы ни поймали событие, всегда можно узнать, где конкретно оно произошло.
Самый глубокий элемент, который вызывает событие, называется «целевым» или «исходным» элементом и доступен как event.target.

Отличия от this (=event.currentTarget):

  • event.target – это исходный элемент, на котором произошло событие, в процессе всплытия он неизменен.
  • this – это текущий элемент, до которого дошло всплытие, на нём сейчас выполняется обработчик.

Например, если стоит только один обработчик form.onclick, то он «поймает» все клики внутри формы. Где бы ни был клик внутри – он всплывёт до элемента , на котором сработает обработчик.

При этом:

  • this (=event.currentTarget) всегда будет сама форма, так как обработчик сработал на ней.
  • event.target будет содержать ссылку на конкретный элемент внутри формы, самый вложенный, на котором произошёл клик.

Возможна и ситуация, когда event.target и this – один и тот же элемент, например если в форме нет других тегов и клик был на самом элементе .

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

Всплытие идёт прямо наверх. Обычно событие будет всплывать наверх и наверх, до элемента , а затем до document , а иногда даже до window , вызывая все обработчики на своем пути.

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

Для остановки всплытия нужно вызвать метод event.stopPropagation() .

Например, здесь при клике на кнопку обработчик body.onclick не сработает:

Код:
Кликни меня

Перехват события. event.stopImmediatePropagation()

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

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

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

Отличия IE8-

Чтобы было проще ориентироваться, я собрал отличия IE8-, которые имеют отношение ко всплытию, в одну секцию.

Их знание понадобится, если вы решите писать на чистом JS, без фреймворков и вам понадобится поддержка IE8-.

Нет свойства event.currentTarget

Обратим внимание, что при назначении обработчика через on свойство у нас есть this , поэтому event.currentTarget , как правило, не нужно, а вот при назначении через attachEvent обработчик не получает this , так что текущий элемент, если нужен, можно будет взять лишь из замыкания.

Вместо event.target в IE8- используется event.srcElement

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

Код: elem.onclick = function(event) {
event = event || window.event;
var target = event.target || event.srcElement;

// ... теперь у нас есть объект события и target
...
}

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

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

Код: event.stopPropagation ? event.stopPropagation() : (event.cancelBubble=true);

Итого
  • При наступлении события – элемент, на котором оно произошло, помечается как «целевой» (event.target).
  • Далее событие сначала двигается вниз от корня документа к event.target, по пути вызывая обработчики, поставленные через addEventListener(...., true).
  • Далее событие двигается от event.target вверх к корню документа, по пути вызывая обработчики, поставленные через on* и addEventListener(...., false).
  • event.target – самый глубокий элемент, на котором произошло событие.
  • event.currentTarget (=this) – элемент, на котором в данный момент сработал обработчик (до которого «доплыло» событие).
  • event.eventPhase – на какой фазе он сработал (погружение =1, всплытие = 3).

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

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

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

Кликните на EM, сработает обработчик на DIV

Как видите при клике на вложенном элементе em срабатывает обработчик на div. Почему так происходит? Читайте дальше и узнаете.

Всплытие

Итак основной принцип всплытия:

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

Например, пусть имеется 3 вложенных элемента FORM > DIV > P, с обработчиком собьытия на каждом:

body * { margin: 10px; border: 1px solid blue; } FORM DIV

Всплытие гарантирует, что клик по внутреннему элементу

Вызовет обработчик click (если он конечно есть) сначала на самом

Такой процесс называется всплытием, потому что события как бы «всплывают» от внутреннего элемента вверх через своих родителей, подобно тому, как всплывает пузырек воздуха в воде, поэтому можно встретить еще определение бабблинг ну это просто от английского слова bubbling — всплывать.

Доступ к целевому элементу event.target

Для того, чтобы узнать на каком именно элементе мы поймали то или иное событие и существует метод event.target. (о объекте event читайте ).

  • event.target – это собственно исходный элемент, на котором и произошло событие.
  • this – это всегда текущий элемент, до которого дошло всплытие, и на нём сейчас выполняется обработчик.

Например, если у вас установлен только один обработчик form.onclick, то он и «поймает» все клики внутри формы. При этом где бы ни был клик внутри – он все равно всплывёт до элемента , на котором и сработает уже обработчик.

При этом:

  • this (=event.currentTarget) всегда будет сама форма, так как обработчик сработал именно на ней.
  • event.target будет содержать ссылку на конкретный элемент внутри формы, самый вложенный, на котором произошёл клик.

В принципе this может совпадать с event.target если кликнули по форме и в форме больше нет никаких элементов.

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

Как правило всплытие события идет прямо наверх и доходит до корневого объекта window.

Но есть возможность остановить всплытие на каком-то промежуточном элементе.

Для того, чтобы остановить всплытие надо вызвать метод event.stopPropagation().

Рассмотрим пример, при клике на кнопку обработчик body.onclick не сработает:

Кликни меня

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

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

Для того, чтобы остановить обработку на текщем элементе, браузеры поддерживают метод event.stopImmediatePropagation(). Этот метод не только предотвратит всплытие, но и останавит обработку событий на текущем элементе.

Погружение

В стандарте, кроме «всплытия» событий, есть ещё и «погружение».

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

Итак имеются 3 стадии прохода события:

  • Событие идет сверху вниз. Эта стадия называется «стадия перехвата».
  • Событие достигло конкретного элемента. Это – «стадия цели».
  • После всего событие начинает всплывать. Это – «стадия всплытия».
  • В стандарте это продемонстрировано так:

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

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

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

    А Чтобы поймать событие на стадии перехвата, как раз и нужно использовать :

    • Аргумент true, то событие будет перехвачено по дороге вниз.
    • Аргумент false, то событие будет поймано при всплытии.
    Примеры

    В примере на , ,

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

    Обработчики сработают в порядке «сверху-вниз»: FORM → DIV → P.

    JS-код здесь такой:

    Var elems = document.querySelectorAll("form,div,p"); // на каждый элемент повесим обработчик на стадии перехвата for (var i = 0; i < elems.length; i++) { elems[i].addEventListener("click", highlightThis, true); }


    Никто вам не мешает назначить обработчики для обеих стадий, вот так:

    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); }

    Кликните по внутреннему элементу

    Чтобы увидеть порядок прохода события:
    Должно быть FORM → DIV → P → P → DIV → FORM. Заметим, что элемент

    Будет участвовать в обоих стадиях.

    Итоги
    • При наступлении события – элемент, на котором произошло событие, помечается как event.target.
    • Событие сначала двигается вниз от корня документа к event.target, по пути вызывая обработчики, поставленные через addEventListener(…., true).
    • Событие двигается от event.target вверх до начала документа, по пути оно вызывает обработчики, поставленные через addEventListener(…., false).

    Каждый обработчик будет иметь доступ к свойствам события:

    • event.target – самый глубокий элемент, на котором собственно и произошло событие.
    • event.currentTarget (=this) – элемент, на котором в данный момент сработал самобработчик (до которого «дошло» событие).
    • event.eventPhase – на какой фазе сработал обработчик события (погружение =1, всплытие = 3).

    Всплытие можно остановить вызовом метода event.stopPropagation(), но делать это не рекомендуется, поскольку событие может вам понадобится для самых неожиданныъ целей.

    mob_info