Написание собственных плагинов под jQuery

(Вольный перевод "Plugins/Authoring")
jQuery - написание собственных расширений
Для удобной работы с jQuery вы вероятно захотите написать собственное расширении (плагин). Это очень хорошо:) Расширение jQuery с помощью плагинов и методов – мощное средство решения многих задач и удобный вариант экономии времени разработки за счет абстрагирования самых распространенных функций. Эта заметка призвана наметить путь, двигаясь по которому вы избежите распространенных ошибок и не упустите свой шанс по написанию собственного плагина.

Приступая к работе.

Чтобы написать расширение для jQuery, нужно начать работу со специального метода объекта jQuery.fn которому присваивается свойство с названием реализуемой нами функции (myPlugin).

  1. jQuery.fn.myPlugin = function () {
  2.  
  3. / / Здесь код нашего супер-плагина
  4.  
  5. };

Здесь нужно обратить внимание что отсутствует знак доллара (Знак $ - название объекта jQuery, которое используется для краткой записи. Примечание пер.). Этот знак не обязателен для использования, особенно когда мы хотим быть уверены что нет других подключенных JavaScript-библиотек, имеющих такое же название. Но из этой ситуации можно выйти используя $ вместе с безымянной функцией.
  1. (function( $ ) {
  2. $.fn.myPlugin = function() {
  3.  
  4. / / Здесь код нашего супер-плагина
  5.  
  6. };
  7. })( jQuery );

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

Контекст.

Теперь , когда у нас есть оболочка, мы можем начать писать сам код плагина. Но до этого пару слов о контексте. В области видимости функции-плагина (здесь понятие функции и плагина очень пересекаются. Примечание мое) , ключевое слово this относится к объекту плагину jQuery. Это обращение позволяет обратиться не только к самому объекту (в данном случае jQuery), но и к его свойствам, методам. С помощью этого слова мы можем добавлять новые функции.

  1. (function( $ ){
  2.  
  3. $.fn.myPlugin = function() {
  4.  
  5. // теперь не нужно обращаться как $(this) потому что
  6. // "this" уже и есть jQuery объект
  7.  
  8. // т.е. $(this) будет теперь рассматриваться как $($('#element'));
  9.  
  10. this.fadeIn('normal', function(){
  11.  
  12. // this – ключевое слово из понятий DOM
  13.  
  14. });
  15.  
  16. };
  17. })( jQuery );
  18. $('#element').myPlugin();

Основы.

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

  1. (function( $ ){
  2.  
  3. $.fn.maxHeight = function() {
  4.  
  5. var max = 0;
  6.  
  7. this.each(function() {
  8. max = Math.max( max, $(this).height() );
  9. });
  10.  
  11. return max;
  12. };
  13. })( jQuery );
  14.  
  15. var tallest = $('div').maxHeight(); // возвращает высоту контейнера tallest

Это простой плагин, возвращающий высоту самого высокого контейнера на странице.

Построение цепочек

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

  1. (function( $ ){
  2.  
  3. $.fn.lockDimensions = function( type ) {
  4.  
  5. return this.each(function() {
  6.  
  7. var $this = $(this);
  8.  
  9. if ( !type || type == 'width' ) {
  10. $this.width( $this.width() );
  11. }
  12.  
  13. if ( !type || type == 'height' ) {
  14. $this.height( $this.height() );
  15. }
  16.  
  17. });
  18.  
  19. };
  20. })( jQuery );

  1. $('div').lockDimensions('width').css('color', 'red');

Поскольку плагин возвращает ключевое слово this в непосредственной видимости, он поддерживает цепочки и jQuery-коллекции могут продолжать манипулировать методами jQuery, например такими как .css. Итак, если ваш плагин не возвращает простые значения, он должен возвращать this в области видимости вашей функции. Кроме того, как вы могли догадаться, аргументы передаваемые вашему плагину – передаются область видимости функции-плагина. Таким образом, в предыдущем примере строка “ширина” становится аргументом для функции-плагина.

Параметры и настройки по умолчанию

Для более сложных и настраиваемых плагинов, которые предоставляют множество вариантов использования, рекомендуется иметь настройки по умолчанию (используя $.extend). Таким образом, вместо вызова плагина с большим количеством аргументов, можно вызвать его с одним аргументом, который является объектом необходимым для изменения. Это вы можете сделать так.

  1. (function( $ ){
  2.  
  3. $.fn.tooltip = function( options ) {
  4.  
  5. // Создаете настройки по умолчанию, которые расширяют ваши опции
  6. var settings = $.extend( {
  7. 'location' : 'top',
  8. 'background-color' : 'blue'
  9. }, options);
  10.  
  11. return this.each(function() {
  12.  
  13. // Здесь код плагина
  14.  
  15. });
  16.  
  17. };
  18. })( jQuery );

  1. $('div').tooltip({
  2. 'location' : 'left'
  3. });

В этом примере, после вызова подсказки плагин с помощью соответствующих опций, переопределяет настройки заданные по умолчанию на “left”, а цвет остается прежним (см. те же настройки по умолчаниию)
  1. {
  2. 'location' : 'left',
  3. 'background-color' : 'blue'
  4. }

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

Пространства имен

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

Методы плагина

Ни в одной ситуации не возможно плагину претендовать на более чем одно пространство имен внутри объекта jQuery.fn объекта.

  1. (function( $ ){
  2.  
  3. $.fn.tooltip = function( options ) {
  4. // ЭТО
  5. };
  6. $.fn.tooltipShow = function( ) {
  7. // ОЧЕНЬ
  8. };
  9. $.fn.tooltipHide = function( ) {
  10. // ПЛОХОЕ РЕШЕНИЕ
  11. };
  12. $.fn.tooltipUpdate = function( content ) {
  13. // !!!
  14. };
  15.  
  16. })( jQuery );

Это рекомендуется чтобы не засорять пространство имен $.fn Чтобы обойти эту ситуацию вы должны собрать все методы плагина в литерал объекта и называть из (то есть ваши методы будут вызываться у одного объекта)

  1. (function( $ ){
  2.  
  3. var methods = {
  4. init : function( options ) {
  5. // ЭТО
  6. },
  7. show : function( ) {
  8. // ОЧЕНЬ
  9. },
  10. hide : function( ) {
  11. // ХОРОШИЙ ПОДХОД
  12. },
  13. update : function( content ) {
  14. // !!!
  15. }
  16. };
  17.  
  18. $.fn.tooltip = function( method ) {
  19.  
  20. // Метод вызывающий логику
  21. if ( methods[method] ) {
  22. return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
  23. } else if ( typeof method === 'object' || ! method ) {
  24. return methods.init.apply( this, arguments );
  25. } else {
  26. $.error( 'Метод ' + method + ' не существует в jQuery.tooltip' );
  27. }
  28.  
  29. };
  30.  
  31. })( jQuery );
  32.  
  33. // вызвать метод для инициализации
  34. $('div').tooltip();
  35.  
  36. // вызвать метод для инициализации
  37. $('div').tooltip({
  38. foo : 'bar'
  39. });
  40.  

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

События

Менее известная особенность метод bind(), который позволяет регистрировать слушателей событий в нашем пространстве имен. Таким образом мы можем разрегистрировать слушателя используя unbind().

  1. (function( $ ){
  2.  
  3. var methods = {
  4. init : function( options ) {
  5.  
  6. return this.each(function(){
  7. $(window).bind('resize.tooltip', methods.reposition);
  8. });
  9.  
  10. },
  11. destroy : function( ) {
  12.  
  13. return this.each(function(){
  14. $(window).unbind('.tooltip');
  15. })
  16.  
  17. },
  18. reposition : function( ) {
  19. // ...
  20. },
  21. show : function( ) {
  22. // ...
  23. },
  24. hide : function( ) {
  25. // ...
  26. },
  27. update : function( content ) {
  28. // ...
  29. }
  30. };
  31.  
  32. $.fn.tooltip = function( method ) {
  33.  
  34. if ( methods[method] ) {
  35. return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
  36. } else if ( typeof method === 'object' || ! method ) {
  37. return methods.init.apply( this, arguments );
  38. } else {
  39. $.error( 'Метод ' + method + ' не существует в jQuery.tooltip' );
  40. }
  41.  
  42. };
  43.  
  44. })( jQuery );
  45. $('#fun').tooltip();
  46. // Через некоторое время
  47. $('#fun').tooltip('destroy');

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

Данные

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

  1. (function( $ ){
  2.  
  3. var methods = {
  4. init : function( options ) {
  5.  
  6. return this.each(function(){
  7.  
  8. var $this = $(this),
  9. data = $this.data('tooltip'),
  10. tooltip = $('<div />', {
  11. text : $this.attr('title')
  12. });
  13.  
  14. // Если плагин не был инициализирован
  15. if ( ! data ) {
  16.  
  17. /*
  18.   Do more setup stuff here
  19.   */
  20.  
  21. $(this).data('tooltip', {
  22. target : $this,
  23. tooltip : tooltip
  24. });
  25.  
  26. }
  27. });
  28. },
  29. destroy : function( ) {
  30.  
  31. return this.each(function(){
  32.  
  33. var $this = $(this),
  34. data = $this.data('tooltip');
  35.  
  36. // Пространство имен FTW
  37. $(window).unbind('.tooltip');
  38. data.tooltip.remove();
  39. $this.removeData('tooltip');
  40.  
  41. })
  42.  
  43. },
  44. reposition : function( ) { // ... },
  45. show : function( ) { // ... },
  46. hide : function( ) { // ... },
  47. update : function( content ) { // ...}
  48. };
  49.  
  50. $.fn.tooltip = function( method ) {
  51.  
  52. if ( methods[method] ) {
  53. return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
  54. } else if ( typeof method === 'object' || ! method ) {
  55. return methods.init.apply( this, arguments );
  56. } else {
  57. $.error( 'Метод ' + method + ' не существует в jQuery.tooltip' ); }
  58.  
  59. };
  60.  
  61. })( jQuery );

Использование data помогает вам отслеживать переменные и состояния между вызовами методов вашего плагина. Разделение пространства имен в одном объекте позволяет легко получить доступ ко всем свойствам вашего плагина из одного объекта.

Резюме и практические советы

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

  • всегда оборачивать наш плагин (function( $ ){ /* тут ваш плагин */ })( jQuery );
  • не оборачивать this в лишние скобки
  • возвращать объект this, чтобы сохранять возможность работы с цепочками
  • вместо передачи большого набора параметров, лучше передавать в качестве аргумента литерал объекта, который модифицирует работу вашего плагина.- Не загромождать объект jQuery.fn более чем одним пространством имен в плагине

Отправить комментарий

CAPTCHA
Этот вопрос задается для того, чтобы выяснить, пьёте ли Вы кофе или рассылаете спам
7 + 9 =
Решите эту простую математическую задачу и введите результат. То есть для 1+3, введите 4.