Делегирование событий в jQuery — какой метод лучше?

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

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

Предполагая, что у меня есть такой блок HTML:

<html>
  <head>
    <title>Test Code</title>
  </head>
  <body>
    <div id="switcher">
      <button id="button1">Button 1</button>
      <button id="button2">Button 1</button>
      <button id="button3">Button 2</button>
      <button id="button4">Button 3</button>
      <button id="button5">Button 4</button>
      <button id="button5">Button 5</button>
      <button id="button6">Button 6</button>
      <button id="button7">Button 7</button>
      <button id="button8">Button 8</button>
      <button id="button9">Button 9</button>
    </div>
<!-- rest of code here -->
  </body>
</html>

При нажатии я хочу:

  1. Получить идентификатор нажатой кнопки (для дальнейших манипуляций).
  2. Переключите класс на «активный» для любой из кнопок.

Вместо этого:

$('#switcher').find('button').click(function(){
  var $element = $(this);      
  var elementid = this.id;
  $element.toggleClass('clicked');
  //rest of code here
});

Я могу сделать это (метод 1)

$('#switcher').click(function(eventName){
  if ($(eventName.target).is('button')) {
    var $element =$(eventName.target);
    var elementid = eventName.target.id;
    $element.toggleClass('active');
    //rest of code here
  }
});

Или так (метод 2)

$('#switcher').on('click', 'button', function(){
  var $element = $(this);
  var elementid = this.id;
  $element.toggleClass('active');
  //rest of code here
});
  1. Являются ли эти 2 метода делегирования на самом деле обеими?
  2. Если да, то какой из двух методов быстрее (или лучше с точки зрения производительности) и лучше обрабатывает делегирование?
  3. Есть ли ограничения браузера?

person Bashiru Ismail Babatunde    schedule 05.10.2016    source источник
comment
Вы определенно должны позволить jQuery обрабатывать делегирование за вас. Это сложнее, чем $(eventName.target).is('button')   -  person Bergi    schedule 05.10.2016
comment
Разумеется, оба метода делают одно и то же: прикрепляют обработчик события к одному элементу. Но я бы не отказался от синтаксического сахара jQuery только из-за незначительного выигрыша в производительности. В любом случае, хороший вопрос.   -  person Álvaro González    schedule 05.10.2016
comment
Я бы предпочел способ 2.   -  person Daniel W.    schedule 05.10.2016
comment
Используйте любой метод, который является правильным инструментом для работы. производительность мало на что влияет.   -  person Kevin B    schedule 05.10.2016
comment
jQuery использует метод 2 в своих документах: learn.jquery.com/events/event-delegation   -  person mhodges    schedule 05.10.2016
comment
Методы 1 и 2 различаются, метод №1 не обрабатывает случай, когда ваши кнопки содержат другой элемент (это не ваш случай, но может быть...). Правильная проверка должна быть if ($(eventName.target).closest('button').length). А что касается события с одним щелчком мыши, единственной проблемой, связанной с производительностью, должно быть время на ремонтопригодность. Скоростные характеристики здесь не имеют значения   -  person A. Wolff    schedule 05.10.2016
comment
.on() (с делегированием или без) также предпочтительнее, потому что вы можете создавать имена для ваших событий и очень легко .off() конкретных обработчиков.   -  person mhodges    schedule 05.10.2016
comment
@demo Ваш пример не делегирование события..   -  person mhodges    schedule 05.10.2016
comment
@demo ↑↑↑ и, кстати, привязать событие click для каждой кнопки, что с точки зрения любой производительности обработки хуже, чем предлагаемые методы   -  person A. Wolff    schedule 05.10.2016
comment
Кстати, $element.id вряд ли сработает. Вам нужно либо this.id, либо $element.attr('id'). В методе 1 вам нужно использовать var $element = $(eventName.target);, чтобы вызвать на нем toggleClass.   -  person Heretic Monkey    schedule 05.10.2016
comment
@MikeMcCaughan Чтобы кэшировать объект, я передал $(this) в переменную $element.   -  person Bashiru Ismail Babatunde    schedule 05.10.2016
comment
Правильно, но не в методе 1. И объект jQuery не имеет свойства id.   -  person Heretic Monkey    schedule 05.10.2016
comment
Ой! Извините, ваш комментарий был действительным. Я отредактирую вопрос, чтобы отразить его. @МайкМакКоган   -  person Bashiru Ismail Babatunde    schedule 05.10.2016


Ответы (1)


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

Это верно для вашей конкретной структуры:

<div id="switcher">
      <button id="button1">Button 1</button>
      <button id="button3">Button 2</button>
</div>

Но если структура DOM изменится, то совсем чуть-чуть:

<div id="switcher">       
    <button id="button1">
        <div class="inner">Button 1</div>
    </button>
    <button id="button3">
        <div class="inner">Button 2</div>
    </button>
</div>

...тогда только "официальное" делегирование событий jQuery будет фактически обнаруживать события кликов для всех дочерних элементов.

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

Имейте в виду, что события щелчка редко (или никогда?) не представляют проблемы с производительностью. Они случаются только время от времени. RequestAnimationFrame, прокрутка или изменение размера могут представлять проблему, а не клики. Единственный случай, когда событие щелчка может быть проблемой производительности, — это если у вас безумно (действительно экстремально!) сложная структура DOM: но в этом случае это, вероятно, означает, что вы должны исправить это в первую очередь.

person taseenb    schedule 05.10.2016
comment
На самом деле, за исключением небольшой ошибки в коде, который был исправлен, оба метода будут работать для приведенного вами примера. .target в if($(eventName.target).is('button')) { получает точный элемент, над которым была выполнена операция щелчка, независимо от того, вложен ли он каким-либо из элементов. Пока он находится под <div id="switcher">. - person Bashiru Ismail Babatunde; 05.10.2016
comment
извините, мой первый пример был немного неправильным. я починил это. если у вас есть элемент внутри button, тогда будет работать только второй метод (делегирование события jquery). - person taseenb; 06.10.2016