Энциклопедия мобильной связи

Введение в всплывающие события. Продвинутая работа с объектом Event на 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:

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

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

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

Кликните на 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(), но делать это не рекомендуется, поскольку событие может вам понадобится для самых неожиданныъ целей.

    Events are actions or occurrences that happen in the system you are programming, which the system tells you about so you can respond to them in some way if desired. For example, if the user clicks a button on a webpage, you might want to respond to that action by displaying an information box. In this article, we discuss some important concepts surrounding events, and look at how they work in browsers. This won"t be an exhaustive study; just what you need to know at this stage.

    Prerequisites: Objective:
    Basic computer literacy, a basic understanding of HTML and CSS, JavaScript first steps .
    To understand the fundamental theory of events, how they work in browsers, and how events may differ in different programming environments.
    A series of fortunate events

    As mentioned above, events are actions or occurrences that happen in the system you are programming - the system produces (or "fires") a signal of some kind when an event occurs, and also provides a mechanism by which some kind of action can be automatically taken (that is, some code running) when the event occurs. For example in an airport when the runway is clear for a plane to take off, a signal is communicated to the pilot, and as a result, they commence piloting the plane.

    In the case of the Web, events are fired inside the browser window, and tend to be attached to a specific item that resides in it - this might be a single element, set of elements, the HTML document loaded in the current tab, or the entire browser window. There are a lot of different types of events that can occur, for example:

    • The user clicking the mouse over a certain element or hovering the cursor over a certain element.
    • The user pressing a key on the keyboard.
    • The user resizing or closing the browser window.
    • A form being submitted.
    • A video being played, or paused, or finishing play.
    • An error occurring.

    You can gather from this (and from glancing at the MDN Event reference) that there are a lot of events that can be responded to.

    Each available event has an event handler , which is a block of code (usually a JavaScript function that you as a programmer create) that will be run when the event fires. When such a block of code is defined to be run in response to an event firing, we say we are registering an event handler . Note that event handlers are sometimes called event listeners - they are pretty much interchangeable for our purposes, although strictly speaking, they work together. The listener listens out for the event happening, and the handler is the code that is run in response to it happening.

    Note : Web events are not part of the core JavaScript language - they are defined as part of the APIs built into the browser.

    A simple example

    Let"s look at a simple example to explain what we mean here. You"ve already seen events and event handlers used in many of the examples in this course already, but let"s recap just to cement our knowledge. In the following example, we have a single , which when pressed, makes the background change to a random color:

    Change color

    Button { margin: 10px };

    The JavaScript looks like so:

    Const btn = document.querySelector("button"); function random(number) { return Math.floor(Math.random() * (number+1)); } btn.onclick = function() { const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body.style.backgroundColor = rndCol; }

    In this code, we store a reference to the button inside a constant called btn , using the Document.querySelector() function. We also define a function that returns a random number. The third part of the code is the event handler. The btn constant points to a element, and this type of object has a number of events that can fire on it, and therefore, event handlers available. We are listening for the click event firing, by setting the onclick event handler property to equal an anonymous function containing code that generates a random RGB color and sets the background-color equal to it.

    This code is run whenever the click event fires on the element, that is, whenever a user clicks on it.

    The example output is as follows:

    It"s not just web pages

    Another thing worth mentioning at this point is that events are not unique to JavaScript - most programming languages have some kind of event model, and the way the model works often differs from JavaScript"s way. In fact, the event model in JavaScript for web pages differs from the event model for JavaScript as it is used in other environments.

    Inline event handlers - don"t use these

    You might also see a pattern like this in your code:

    Press me function bgChange() { const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body.style.backgroundColor = rndCol; }

    The earliest method of registering event handlers found on the Web involved event handler HTML attributes (or inline event handlers ) like the one shown above - the attribute value is literally the JavaScript code you want to run when the event occurs. The above example invokes a function defined inside a element on the same page, but you could also insert JavaScript directly inside the attribute, for example:

    Press me

    You can find HTML attribute equivalents for many of the event handler properties; however, you shouldn"t use these - they are considered bad practice. It might seem easy to use an event handler attribute if you are just doing something really quick, but they very quickly become unmanageable and inefficient.

    For a start, it is not a good idea to mix up your HTML and your JavaScript, as it becomes hard to parse - keeping your JavaScript all in one place is better; if it is in a separate file you can apply it to multiple HTML documents.

    Even in a single file, inline event handlers are not a good idea. One button is OK, but what if you had 100 buttons? You"d have to add 100 attributes to the file; it would very quickly turn into a maintenance nightmare. With JavaScript, you could easily add an event handler function to all the buttons on the page no matter how many there were, using something like this:

    Const buttons = document.querySelectorAll("button"); for (let i = 0; i < buttons.length; i++) { buttons[i].onclick = bgChange; } buttons.forEach(function(button) { button.onclick = bgChange; });

    Note : Separating your programming logic from your content also makes your site more friendly to search engines.

    addEventListener() and removeEventListener()

    The newest type of event mechanism is defined in the Document Object Model (DOM) Level 2 Events Specification, which provides browsers with a new function - addEventListener() . This functions in a similar way to the event handler properties, but the syntax is obviously different. We could rewrite our random color example to look like this:

    Const btn = document.querySelector("button"); function bgChange() { const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body.style.backgroundColor = rndCol; } btn.addEventListener("click", bgChange);

    Inside the addEventListener() function, we specify two parameters - the name of the event we want to register this handler for, and the code that comprises the handler function we want to run in response to it. Note that it is perfectly appropriate to put all the code inside the addEventListener() function, in an anonymous function, like this:

    Btn.addEventListener("click", function() { var rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body.style.backgroundColor = rndCol; });

    This mechanism has some advantages over the older mechanisms discussed earlier. For a start, there is a counterpart function, removeEventListener() , which removes a previously added listener. For example, this would remove the listener set in the first code block in this section:

    Btn.removeEventListener("click", bgChange);

    This isn"t significant for simple, small programs, but for larger, more complex programs it can improve efficiency to clean up old unused event handlers. Plus, for example, this allows you to have the same button performing different actions in different circumstances - all you have to do is add or remove event handlers as appropriate.

    Second, you can also register multiple handlers for the same listener. The following two handlers wouldn"t both be applied:

    MyElement.onclick = functionA; myElement.onclick = functionB;

    The second line overwrites the value of onclick set by the first line. This would work, however:

    MyElement.addEventListener("click", functionA); myElement.addEventListener("click", functionB);

    Both functions would now run when the element is clicked.

    In addition, there are a number of other powerful features and options available with this event mechanism. These are a little out of scope for this article, but if you want to read up on them, have a look at the addEventListener() and removeEventListener() reference pages.

    What mechanism should I use?

    Of the three mechanisms, you definitely shouldn"t use the HTML event handler attributes - these are outdated, and bad practice, as mentioned above.

    The other two are relatively interchangeable, at least for simple uses:

    • Event handler properties have less power and options, but better cross-browser compatibility (being supported as far back as Internet Explorer 8). You should probably start with these as you are learning.
    • DOM Level 2 Events (addEventListener() , etc.) are more powerful, but can also become more complex and are less well supported (supported as far back as Internet Explorer 9). You should also experiment with these, and aim to use them where possible.

    The main advantages of the third mechanism are that you can remove event handler code if needed, using removeEventListener() , and you can add multiple listeners of the same type to elements if required. For example, you can call addEventListener("click", function() { ... }) on an element multiple times, with different functions specified in the second argument. This is impossible with event handler properties because any subsequent attempts to set a property will overwrite earlier ones, e.g.:

    Element.onclick = function1; element.onclick = function2; etc.

    Note : If you are called upon to support browsers older than Internet Explorer 8 in your work, you may run into difficulties, as such ancient browsers use different event models from newer browsers. But never fear, most JavaScript libraries (for example jQuery) have built-in functions that abstract away cross-browser differences. Don"t worry about this too much at this stage in your learning journey.

    Other event concepts

    In this section, we briefly cover some advanced concepts that are relevant to events. It is not important to understand these concepts fully at this point, but they might serve to explain some code patterns you"ll likely come across from time to time.

    Event objects

    Sometimes inside an event handler function, you might see a parameter specified with a name such as event , evt , or simply e . This is called the event object , and it is automatically passed to event handlers to provide extra features and information. For example, let"s rewrite our random color example again slightly:

    Function bgChange(e) { const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; e.target.style.backgroundColor = rndCol; console.log(e); } btn.addEventListener("click", bgChange);

    Here you can see that we are including an event object, e , in the function, and in the function setting a background color style on e.target - which is the button itself. The target property of the event object is always a reference to the element that the event has just occurred upon. So in this example, we are setting a random background color on the button, not the page.

    Note : You can use any name you like for the event object - you just need to choose a name that you can then use to reference it inside the event handler function. e / evt / event are most commonly used by developers because they are short and easy to remember. It"s always good to be consistent - with yourself, and with others if possible.

    e.target is incredibly useful when you want to set the same event handler on multiple elements and do something to all of them when an event occurs on them. You might, for example, have a set of 16 tiles that disappear when they are clicked on. It is useful to always be able to just set the thing to disappear as e.target , rather than having to select it in some more difficult way. In the following example (see useful-eventtarget.html for the full source code; also see it running live here), we create 16 elements using JavaScript. We then select all of them using document.querySelectorAll() , then loop through each one, adding an onclick handler to each that makes it so that a random color is applied to each one when clicked:

    Const divs = document.querySelectorAll("div"); for (let i = 0; i < divs.length; i++) { divs[i].onclick = function(e) { e.target.style.backgroundColor = bgChange(); } }

    The output is as follows (try clicking around on it - have fun):

    Hidden example Useful event target example div { height: 100px; width: 25%; float: left; } for (let i = 1; i

    Понравилась статья? Поделитесь с друзьями!
    Была ли эта статья полезной?
    Да
    Нет
    Спасибо, за Ваш отзыв!
    Что-то пошло не так и Ваш голос не был учтен.
    Спасибо. Ваше сообщение отправлено
    Нашли в тексте ошибку?
    Выделите её, нажмите Ctrl + Enter и мы всё исправим!