Как стать автором
Обновить

Использование событий в jQuery плагинах

Время на прочтение5 мин
Количество просмотров8.3K
Основной целью данной статьи является: показать различия между традиционной реализацией jQuery плагина и реализацией с применением событий. В статье будет: о традиционной реализации jQuery плагина, о работе с событиями в jQuery, и попытка заменить методы или callback-функции плагина событиями.

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

1. Теория
1.А. Традиционный плагин jQuery
1.Б. Область видимости переменных
1.В. Работа с событиями в jQuery
1.Г. Применение событий в плагинах
1.Д. Недостатки событий
2. Пример простого приложения с дроблением на плагины
3. Заключение, вывод
4. Список литературы


1. Теория



1.А. Традиционный плагин jQuery


Создание традиционного jQuery плагина задача достаточно тривиальная. Для этого необходимо добавить в пространство $.fn новый метод.

Пример 1 (создание плагина myPlugin):

(function( $ ) {
  $.fn.myPlugin = function(options) {
  
	// Переменная options - настройки плагина
	// Объект $(this) - доступ к объекту jQuery с выбранным элементом, на который навешен плагин

	// Код плагина будет располагаться здесь

  };
})( jQuery );


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

Но часто нам необходимо получить данные или состояние плагина. Хорошим примером является DatePicker.

Мне известно несколько решений для получения данных:
  • Р.1.А. Вызов метода (или функции).
    Пример 2: $('input.date').datePicker('getDate'); $('input.date').datePicker('isDisabled').
    Недостаток: нет возможности отследить изменения (например, пользователь выбрал другое значение);
  • Р.1.Б. Передача callback-функции.
    Пример 3: $('input.date').datePicker({onChange: onChangeCallback}); $('input.date').datePicker({onDisable: onDisableCallback}).
    Недостаток: Усложнение реализации плагина: необходимо реализовать вызов callback-функции, подписку на событие нескольких слушателей;
  • Р.1.В. События.
    Пример 4: $('input.date').on('change', onChangeHandler); $('input.date').on('disable', onDisableHandler).
    Подробней о достоинствах и недостатках дальше.


1.Б. Область видимости переменных

Проблема в реализации методов Р.1.А и Р.1.Б заключается в том, что при следующем вызове $(element).datePicker(...) повторно выполняется «конструктор» плагина. Конечно это легко отслеживается путем проверки передаваемых параметров: если передан объект (опции) — это инициализация; если передана строка — необходим вызов метода. Как говорится, «баг это или фича» — пока не хватает опыта понять.

Но я столкнулся с проблемой областей видимости переменных.

Пример 5: Демонстрация проблемы областей видимости

(function( $ ) {  
  // Опции
  var options = {
    date: '00-00-0000'
  },
  // Методы
  methods = {
    getDate: function()
    {
      return options.date;
    }
  };
  
  // Плагин
  $.fn.myPlugin = function(o)
  {
    if (typeof o === 'string' && methods[o] !== null) {
        return methods[o].apply();
    }
    
    options = o || options;
    
    $(this).text(options.date);
    
  };
  
  // Инициализация плагина
  $('[data-test]').myPlugin({
    date: '10-10-2013'
  });
  
  // Получение данных
  alert($('[data-test]').myPlugin('getDate'));
  
})( jQuery );


На данном этапе все просто: создаем плагин, который выводит дату из опций.

Но проблема возникает, когда необходимо поместить на страницу больше одного плагина данного типа.

Пример 6: Больше одного плагина на странице

Как видим из примера 6 — переменная options, которая была вынесена за пределы плагина — перезаписалась данными при инициализации плагина 2.

Решения для примера 6:

  • Р.2.A. В объекте options хранить данные для инициализации всех плагинов (усложнение кода);
  • Р.2.Б. Крепить данные инициализации к DOM-объекту (с моей точки зрения: неплохое решение);
  • Р.2.В. Использование событий. Вызов методов при помощи $(...).trigger(...). В конце я приведу пример, который лишен данного недостатка.


1.В. Работа с событиями в jQuery

При помощи библиотеки jQuery мы можем как создавать «слушателей» для событий $('.link').on('click', onClickHandler), так и вызывать (провоцировать) события $('.link').trigger('click').

Обратимся к документации, посмотрим параметры обеих функций:

В общих чертах функция on имеет параметры:
  • events — список событий которые необходимо слушать;
  • handler — функция-обработчик события, которая будет вызвана при совершении любого события из списка events.


Функция trigger имеет параметры:
  • eventType — название события, которое необходимо вызвать;
  • extraParameters — массив или объект, содержащий параметры, которые необходимо передать обработчику события.

Пример 7: Демонстрирующий работу событий

$(function() {
  
  $(document).on('myEvent', function(event, p) {
    alert('a: ' + p.a + '; b: ' + p.b);
  });
  
  $(document).trigger('myEvent', {
    a: '1',
    b: '2'
  });
  
});


1.Г. Применение событий в плагинах

Чтобы избавиться от проблемы с областью видимости переменных (описанной в примере П.6) и проблемой с навешиванием нескольких слушателей (описанной в решении Р.1.Б) я прибегнул к использованию событий и оберток, реализованных в jQuery (1.В).

Пример 7: Реализация событий в плагине

(function( $ ) {
  
  // Объявление плагина
  $.fn.datePicker = function(options)
  {
  
	var self = $(this),
        options = options || {
          year: 2012,
          month: 1,
          day: 1
        };

    var date = new Date(options.year, options.month, options.day),
        d = new Date(options.year, options.month, 1),
        table = $('<table />'),
        tr = $('<tr>');
    
    tr.appendTo(table);
    
    // Добавляем начало месяца
    for (i=0; i < d.getDay(); i++) {
      tr.append('<td />');
    }
    
    // Добавляем даты
    while (d.getMonth() == date.getMonth()) {
      if (i % 7 == 0) {
        tr = $('<tr />');
        tr.appendTo(table);
        i = 0;
      }
      
      var td = $('<td>' + d.getDate() + '</td>');
      td.data('date', d.toString());
      tr.append(td);
      
      d.setDate(d.getDate() + 1);
      i++;
    }
    
    // Добавляем конец месяца
    for (i=0; i < 7 - d.getDay(); i++) {
      tr.append('<td />');
    }
   
    table.appendTo(self);
    
    // При клике на ячейку таблицы генерируем событие 'change' для плагина
    table.find('td').on('click', function() {
      // Вторым параметром передаем дату
      self.trigger('change', $(this).data('date'));
    });
    
    return self;
    
  };
  
  
  // Инициализация плагина
  $('[data-datePiceker]').datePicker();
  
  
  // Навешивание слушателя для события
  $('[data-datePiceker]').on('change', function(event, date) {
    alert(date);
  });
  
})( jQuery );


Что мы получили:
  • «конструктор» вызывается только один раз;
  • мы можем навесить множество «слушателей», которые будут получать информацию о состоянии плагина;
  • переменные, относящиеся к плагину находятся в теле функции, и не зависят от других инициализаций данного плагина.

Пример 8 Демонстрирующий работу нескольких инициализаций одного плагина П.7

1.Д. Недостатки событий

Конечно данный подход меняет привычный подход к работе с плагином, я имею ввиду отсутствие традиционных методов получения данных, например $(...).datePicker('getDate'), но тем не менее на данном этапе моего личного развития, как программиста, данный способ решает некоторые мои проблемы. Я лично, считаю данный поход довольно универсальным, и с недостатками пока не сталкивался — если читатель знает о таковых, пожалуйста не молчите, и хочу так же попросить писать как можно доступней и адекватней.

2. Пример простого приложения с дроблением на плагины


Для тренировки и обкатки событий написал несколько маленьких клиентских приложений:


3. Вывод, заключение


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

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

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

Спасибо за внимание!

4. Используемая литература


  1. twitter.github.com/flight
  2. api.jquery.com/trigger
  3. api.jquery.com/on
  4. docs.jquery.com/Plugins/Authoring


5. Литература от комментаторов


  1. jQuery UI: Фабрика виджитов
  2. Очень большая подборка разнообразных паттернов проектирования и примеров из популярных фреймверков
  3. Судя по англ. названию Паттерны рефакторинга (еще не изучал)
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Мнение о данной статье:
62.7% Статья полезная, необходимо продолжение79
37.3% Статья банальна, информация давно известна47
Проголосовали 126 пользователей. Воздержались 46 пользователей.
Теги:
Хабы:
+19
Комментарии14

Публикации

Истории

Работа

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн