Событие onclick в javascript и jquery на примерах

Parameter Values

Parameter Description
event Required. A String that specifies the name of the event.Note: Do not use the «on» prefix. For example, use «click» instead of «onclick».For a list of all HTML DOM events, look at our complete HTML DOM Event Object Reference.
function Required. Specifies the function to run when the event occurs. When the event occurs, an event object is passed to the function as the first parameter. The type of the event object depends on the specified event. For example, the «click» event belongs to the MouseEvent object.
useCapture Optional. A Boolean value that specifies whether the event should be executed in the capturing or in the bubbling phase. Possible values:
  • true — The event handler is executed in the capturing phase
  • false- Default. The event handler is executed in the bubbling phase

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

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


Приём проектирования «поведение» состоит из двух частей:

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

Например, здесь HTML-атрибут добавляет кнопкам поведение: «увеличить значение при клике»:

Если нажать на кнопку – значение увеличится. Конечно, нам важны не счётчики, а общий подход, который здесь продемонстрирован.

Элементов с атрибутом может быть сколько угодно. Новые могут добавляться в HTML-код в любой момент. При помощи делегирования мы, фактически, добавили новый «псевдостандартный» атрибут в HTML, который добавляет элементу новую возможность («поведение»).

Всегда используйте метод для обработчиков на уровне документа

Когда мы устанавливаем обработчик событий на объект , мы всегда должны использовать метод , а не , т.к. в случае последнего могут возникать конфликты: новые обработчики будут перезаписывать уже существующие.

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

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

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

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

Мы можем комбинировать несколько вариантов поведения на одном элементе.

Шаблон «поведение» может служить альтернативой для фрагментов JS-кода в вёрстке.

Свои события

Как мы уже знаем, в современных браузерах DOM-элементы могут генерировать произвольные события при помощи встроенных методов, а в IE8- это возможно с использованием фреймворка, к примеру, jQuery.

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

Для этого модифицируем функцию :

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

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

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

Результат menu.js menu.css index.html

Внимание, инкапсуляция!

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

Строго говоря, он вообще не знает про то, как устроено меню, есть ли там ссылки и какие, или там вообще всё реализовано через кнопки.

Меню для него – «чёрный ящик». Корневой элемент – точка доступа к его функциональности. Событие – не то, которое произошло на ссылке, а «переработанный вариант», интерпретация действия со стороны меню.

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

Ещё раз – внешний код не имеет права залезать внутрь DOM-структуры меню, ставить там обработчики и так далее.

Possible mistakes

If you’re starting to work with events – please note some subtleties.

We can set an existing function as a handler:

But be careful: the function should be assigned as , not .

If we add parentheses, then becomes is a function call. So the last line actually takes the result of the function execution, that is (as the function returns nothing), and assigns it to . That doesn’t work.

…On the other hand, in the markup we do need the parentheses:

The difference is easy to explain. When the browser reads the attribute, it creates a handler function with body from the attribute content.

So the markup generates this property:

Don’t use for handlers.

Such a call won’t work:

DOM-property case matters.

Assign a handler to , not , because DOM properties are case-sensitive.

Погружение

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

Стандарт DOM Events описывает 3 фазы прохода события:

  1. Фаза погружения (capturing phase) – событие сначала идёт сверху вниз.
  2. Фаза цели (target phase) – событие достигло целевого(исходного) элемента.
  3. Фаза всплытия (bubbling stage) – событие начинает всплывать.

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

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

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

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

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

Существуют два варианта значений опции :

  • Если аргумент (по умолчанию), то событие будет поймано при всплытии.
  • Если аргумент , то событие будет перехвачено при погружении.

Обратите внимание, что хоть и формально существует 3 фазы, 2-ую фазу («фазу цели»: событие достигло элемента) нельзя обработать отдельно, при её достижении вызываются все обработчики: и на всплытие, и на погружение. Давайте посмотрим и всплытие и погружение в действии:


Давайте посмотрим и всплытие и погружение в действии:

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

Если вы кликните по , то последовательность следующая:

  1. → → → (фаза погружения, первый обработчик)
  2. (фаза цели, срабатывают обработчики, установленные и на погружение и на всплытие, так что выведется два раза)
  3. → → → (фаза всплытия, второй обработчик)

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

Чтобы убрать обработчик , нужна та же фаза

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

На каждой фазе разные обработчики на одном элементе срабатывают в порядке назначения

Если у нас несколько обработчиков одного события, назначенных на один элемент, в рамках одной фазы, то их порядок срабатывания – тот же, в котором они установлены:

JS Tutorial

JS HOMEJS IntroductionJS Where ToJS OutputJS StatementsJS SyntaxJS CommentsJS VariablesJS OperatorsJS ArithmeticJS AssignmentJS Data TypesJS FunctionsJS ObjectsJS EventsJS StringsJS String MethodsJS NumbersJS Number MethodsJS ArraysJS Array MethodsJS Array SortJS Array IterationJS DatesJS Date FormatsJS Date Get MethodsJS Date Set MethodsJS MathJS RandomJS BooleansJS ComparisonsJS ConditionsJS SwitchJS Loop ForJS Loop WhileJS BreakJS Type ConversionJS BitwiseJS RegExpJS ErrorsJS ScopeJS HoistingJS Strict ModeJS this KeywordJS LetJS ConstJS Arrow FunctionJS DebuggingJS Style GuideJS Best PracticesJS MistakesJS PerformanceJS Reserved WordsJS VersionsJS Version ES5JS Version ES6JS JSON

JavaScript

JS Array concat() constructor copyWithin() entries() every() fill() filter() find() findIndex() forEach() from() includes() indexOf() isArray() join() keys() length lastIndexOf() map() pop() prototype push() reduce() reduceRight() reverse() shift() slice() some() sort() splice() toString() unshift() valueOf()

JS Boolean constructor prototype toString() valueOf()

JS Classes constructor() extends static super

JS Date constructor getDate() getDay() getFullYear() getHours() getMilliseconds() getMinutes() getMonth() getSeconds() getTime() getTimezoneOffset() getUTCDate() getUTCDay() getUTCFullYear() getUTCHours() getUTCMilliseconds() getUTCMinutes() getUTCMonth() getUTCSeconds() now() parse() prototype setDate() setFullYear() setHours() setMilliseconds() setMinutes() setMonth() setSeconds() setTime() setUTCDate() setUTCFullYear() setUTCHours() setUTCMilliseconds() setUTCMinutes() setUTCMonth() setUTCSeconds() toDateString() toISOString() toJSON() toLocaleDateString() toLocaleTimeString() toLocaleString() toString() toTimeString() toUTCString() UTC() valueOf()

JS Error name message

JS Global decodeURI() decodeURIComponent() encodeURI() encodeURIComponent() escape() eval() Infinity isFinite() isNaN() NaN Number() parseFloat() parseInt() String() undefined unescape()

JS JSON parse() stringify()

JS Math abs() acos() acosh() asin() asinh() atan() atan2() atanh() cbrt() ceil() cos() cosh() E exp() floor() LN2 LN10 log() LOG2E LOG10E max() min() PI pow() random() round() sin() sqrt() SQRT1_2 SQRT2 tan() tanh() trunc()

JS Number constructor isFinite() isInteger() isNaN() isSafeInteger() MAX_VALUE MIN_VALUE NEGATIVE_INFINITY NaN POSITIVE_INFINITY prototype toExponential() toFixed() toLocaleString() toPrecision() toString() valueOf()

JS OperatorsJS RegExp constructor compile() exec() g global i ignoreCase lastIndex m multiline n+ n* n? n{X} n{X,Y} n{X,} n$ ^n ?=n ?!n source test() toString() (x|y) . \w \W \d \D \s \S \b \B \0 \n \f \r \t \v \xxx \xdd \uxxxx

JS Statements break class continue debugger do…while for for…in for…of function if…else return switch throw try…catch var while

JS String charAt() charCodeAt() concat() constructor endsWith() fromCharCode() includes() indexOf() lastIndexOf() length localeCompare() match() prototype repeat() replace() search() slice() split() startsWith() substr() substring() toLocaleLowerCase() toLocaleUpperCase() toLowerCase() toString() toUpperCase() trim() valueOf()

Object handlers: handleEvent

We can assign not just a function, but an object as an event handler using . When an event occurs, its method is called.

For instance:

As we can see, when receives an object as the handler, it calls in case of an event.

We could also use a class for that:

Here the same object handles both events. Please note that we need to explicitly setup the events to listen using . The object only gets and here, not any other types of events.

The method does not have to do all the job by itself. It can call other event-specific methods instead, like this:

Now event handlers are clearly separated, that may be easier to support.

Заметки

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

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

  • Позволяет добавлять множество обработчиков для одного события. Это особенно полезно для DHTML библиотек или Mozilla extensions, которые должны работать в условиях использования сторонних библиотек/расширений.
  • Предоставляет точный контроль фазы срабатывания(вызова) обработчика (захват или всплытие)
  • Срабатывает на любом DOM элементе, а не только на HTML элементах.

Ниже описан другой, .

Добавление слушателя во время обработки события

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

Несколько одинаковых слушателей события

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

Значение  в обработчике

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

В примере выше значение переменной  внутри  при вызове событием клика равно таблице ‘t’. Это противоположно поведению, которое возникает, если обработчик добавлен в HTML-разметке:

<table id="t" onclick="modifyText();">
  . . .

Значение переменной  внутри  при вызове событием клика будет равно ссылке на глобальный (window) объект (или  при использовании strict mode)

Note: В JavaScript 1.8.5 введён метод  , который позволяет указать значение, которое должно быть использовано для всех вызовов данной функции. Он позволяет вам легко обходить ситуации, в которых не ясно, чему будет равно this, в зависимости от того, в каком контексте будет вызвана ваша функция. заметьте, также, что Вам будет необходимо иметь внешню ссылку на слушатель, чтобы Вы могли удалить его позже.

Пример с использованием  и без него:

var Something = function(element) {
  this.name = 'Something Good';
  this.onclick1 = function(event) {
    console.log(this.name); // undefined, так как this является элементом
  };
  this.onclick2 = function(event) {
    console.log(this.name); // 'Something Good', так как в this передано значение объекта Something
  };
  element.addEventListener('click', this.onclick1, false);
  element.addEventListener('click', this.onclick2.bind(this), false); // Trick
}

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

var Something = function(element) {
  this.name = 'Something Good';
  this.handleEvent = function(event) {
    console.log(this.name); // 'Something Good', так как this является объектом Something
    switch(event.type) {
      case 'click':
        // код обработчика...
        break;
      case 'dblclick':
        // код обработчика...
        break;
    }
  };

  // В этом случае слушатели хранятся в this, а не в this.handleEvent
  element.addEventListener('click', this, false);
  element.addEventListener('dblclick', this, false);

  // Вы можете напрямую удалять слушатели
  element.removeEventListener('click', this, false);
  element.removeEventListener('dblclick', this, false);
}

Наследство Internet Explorer и attachEvent

В Internet Explorer младше 9 версии, вы можете использовать  вместо стандартного . Для поддержки IE, пример выше может быть модифицирован следующим образом:

if (el.addEventListener) {
  el.addEventListener('click', modifyText, false); 
} else if (el.attachEvent)  {
  el.attachEvent('onclick', modifyText);
}

У  есть недостаток:  будет ссылаться на объект , а не на элемент, на котором он был вызван.

Browser Support

The numbers in the table specifies the first browser version that fully supports these methods.

Method
addEventListener() 1.0 9.0 1.0 1.0 7.0
removeEventListener() 1.0 9.0 1.0 1.0 7.0

Note: The and methods are not supported in IE 8 and earlier versions. However, for these specific browser versions, you can use the method to attach an event handlers to the element, and the method to remove it:

element.attachEvent(event, function);element.detachEvent(event, function);

Example

Cross-browser solution:

var x = document.getElementById(«myBtn»);if (x.addEventListener) {     // For all major browsers, except IE 8 and earlier  x.addEventListener(«click», myFunction);} else if (x.attachEvent) {   // For IE 8 and earlier versions   x.attachEvent(«onclick», myFunction);}

addEventListener

The fundamental problem of the aforementioned ways to assign handlers – we can’t assign multiple handlers to one event.

Let’s say, one part of our code wants to highlight a button on click, and another one wants to show a message on the same click.

We’d like to assign two event handlers for that. But a new DOM property will overwrite the existing one:

Developers of web standards understood that long ago and suggested an alternative way of managing handlers using special methods and . They are free of such a problem.

The syntax to add a handler:

Event name, e.g. .
The handler function.
An additional optional object with properties:
  • : if , then the listener is automatically removed after it triggers.
  • : the phase where to handle the event, to be covered later in the chapter Bubbling and capturing. For historical reasons, can also be , that’s the same as .
  • : if , then the handler will not call , we’ll explain that later in Browser default actions.

To remove the handler, use :

Removal requires the same function

To remove a handler we should pass exactly the same function as was assigned.

This doesn’t work:

The handler won’t be removed, because gets another function – with the same code, but that doesn’t matter, as it’s a different function object.

Here’s the right way:


Please note – if we don’t store the function in a variable, then we can’t remove it. There’s no way to “read back” handlers assigned by .

Multiple calls to allow to add multiple handlers, like this:

As we can see in the example above, we can set handlers both using a DOM-property and . But generally we use only one of these ways.

For some events, handlers only work with

There exist events that can’t be assigned via a DOM-property. Only with .

For instance, the event, that triggers when the document is loaded and DOM is built.

So is more universal. Although, such events are an exception rather than the rule.

Погружение

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

Оно гораздо менее востребовано, но иногда, очень редко, знание о нём может быть полезным.

Строго говоря, стандарт выделяет целых три стадии прохода события:

  1. Событие сначала идёт сверху вниз. Эта стадия называется «стадия перехвата» (capturing stage).
  2. Событие достигло целевого элемента. Это – «стадия цели» (target stage).
  3. После этого событие начинает всплывать. Это – «стадия всплытия» (bubbling stage).

В стандарте DOM Events 3 это продемонстрировано так:

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

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

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

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

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

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

Есть события, которые не всплывают, но которые можно перехватить

Бывают события, которые можно поймать только на стадии перехвата, а на стадии всплытия – нельзя…

Например, таково событие фокусировки на элементе onfocus. Конечно, это большая редкость, такое исключение существует по историческим причинам.

用法说明

事件监听回调

事件监听器可以被指定为回调函数或实现 的对象,其 方法用作回调函数。

回调函数本身具有与方法相同的参数和返回值;也就是说,回调接受一个参数:一个基于 的对象,描述已发生的事件,并且它不返回任何内容。

例如,一个可用于处理和的事件处理函数可以像这样:

function eventHandler(event) {
  if (event.type == fullscreenchange) {
    /* handle a full screen toggle */
  } else /* fullscreenerror */ {
    /* handle a full screen toggle error */
  }
}

option支持的安全检测

在旧版本的DOM的规定中, 的第三个参数是一个布尔值表示是否在捕获阶段调用事件处理程序。随着时间的推移,很明显需要更多的选项。与其在方法之中添加更多参数(传递可选值将会变得异常复杂),倒不如把第三个参数改为一个包含了各种属性的对象,这些属性的值用来被配置删除事件侦听器的过程。

因为旧版本的浏览器(以及一些相对不算古老的)仍然假定第三个参数是布尔值,你需要编写一些代码来有效地处理这种情况。你可以对每一个你感兴趣的options值进行特性检测。

如果你想检测  值可以参考下面这个例子:

var passiveSupported = false;

try {
  var options = Object.defineProperty({}, "passive", {
    get: function() {
      passiveSupported = true;
    }
  });

  window.addEventListener("test", null, options);
} catch(err) {}

这段代码为  属性创建了一个带有getter函数的  对象;getter设定了一个标识, ,被调用后就会把其设为。那意味着如果浏览器检查  对象上的  值时,  将会被设置为 ;否则它将保持 。然后我们调用  去设置一个指定这些选项的空事件处理器,这样如果浏览器将第三个参数认定为对象的话,这些选项值就会被检查。

你可以利用这个方法检查options之中任一个值。只需使用与上面类似的代码,为选项设定一个getter。

然后,当你想实际创建一个是否支持options的事件侦听器时,你可以这样做:

someElement.addEventListener("mouseup", handleMouseUp, passiveSupported
                               ? { passive: true } : false);

我们在  这里添加了一个。对于第三个参数,如果  是  ,我们传递了一个  值为  的  对象;如果相反的话,我们知道要传递一个布尔值,于是就传递  作为  的参数。

如果你愿意,你可以用一个类似 Modernizr 或 Detect It 的第三方库来帮助你做这项测试。

你可以在 Web Incubator Community Group 里关于 的文章中了解更多。

Event handlers

To react on events we can assign a handler – a function that runs in case of an event.

Handlers are a way to run JavaScript code in case of user actions.

There are several ways to assign a handler. Let’s see them, starting from the simplest one.

A handler can be set in HTML with an attribute named .

For instance, to assign a handler for an , we can use , like here:

On mouse click, the code inside runs.

Please note that inside we use single quotes, because the attribute itself is in double quotes. If we forget that the code is inside the attribute and use double quotes inside, like this: , then it won’t work right.

An HTML-attribute is not a convenient place to write a lot of code, so we’d better create a JavaScript function and call it there.

Here a click runs the function :

As we know, HTML attribute names are not case-sensitive, so works as well as and … But usually attributes are lowercased: .


We can assign a handler using a DOM property .

For instance, :

If the handler is assigned using an HTML-attribute then the browser reads it, creates a new function from the attribute content and writes it to the DOM property.

So this way is actually the same as the previous one.

These two code pieces work the same:

  1. Only HTML:

  2. HTML + JS:

In the first example, the HTML attribute is used to initialize the , while in the second example – the script, that’s all the difference.

As there’s only one property, we can’t assign more than one event handler.

In the example below adding a handler with JavaScript overwrites the existing handler:

To remove a handler – assign .

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

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

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

Для этого нужно вызвать метод .

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

event.stopImmediatePropagation()

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

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

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

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

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

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

Например:

  1. Мы делаем вложенное меню. Каждое подменю обрабатывает клики на своих элементах и делает для них , чтобы не срабатывало внешнее меню.
  2. Позже мы решили отслеживать все клики в окне для какой-то своей функциональности, к примеру, для статистики – где вообще у нас кликают люди. Некоторые системы аналитики так делают. Обычно используют , чтобы отлавливать все клики.
  3. Наша аналитика не будет работать над областью, где клики прекращаются . Увы, получилась «мёртвая зона».

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

Итого

Чтобы сгенерировать событие из кода, вначале надо создать объект события.

Базовый конструктор принимает обязательное имя события и – объект с двумя свойствами:

  • чтобы событие всплывало.
  • если мы хотим, чтобы работал.

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

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

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

Весьма часто, когда разработчик хочет сгенерировать встроенное событие – это вызвано «кривой» архитектурой кода.

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

  • Либо как явный и грубый хак, чтобы заставить работать сторонние библиотеки, в которых не предусмотрены другие средства взаимодействия.
  • Либо для автоматического тестирования, чтобы скриптом «нажать на кнопку» и посмотреть, произошло ли нужное действие.

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

Итого

Делегирование событий – это здорово! Пожалуй, это один из самых полезных приёмов для работы с DOM.

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

Алгоритм:

  1. Вешаем обработчик на контейнер.
  2. В обработчике проверяем исходный элемент .
  3. Если событие произошло внутри нужного нам элемента, то обрабатываем его.

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

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

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

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

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

Итого

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

  • Затем событие сначала двигается вниз от корня документа к , по пути вызывая обработчики, поставленные через , где – это сокращение для .
  • Далее обработчики вызываются на целевом элементе.
  • Далее событие двигается от вверх к корню документа, по пути вызывая обработчики, поставленные через и без третьего аргумента или с третьим аргументом равным .

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

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

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

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

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

Тоже самое справедливо для обработчиков событий. Код, который «навесил» обработчик на конкретный элемент, знает максимум деталей об элементе и его предназначении. Например, обработчик на определённом скорее всего подходит только для этого конкретного , он знает все о нём, поэтому он должен отработать первым. Далее имеет смысл передать обработку события родителю – он тоже понимает, что происходит, но уже менее детально, далее – выше, и так далее, до самого объекта , обработчик на котором реализовывает самую общую функциональность уровня документа.

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


С этим читают