Антон Шевчук // Web-разработчик

jQuery для начинающих. Часть 7. Пишем плагины // JavaScript

jQuery Logo

Если вы читали предыдущие статьи из этой серии, то вы наверное уже пробовали разрабатывать свой плагин, если нет, то можем начать вместе…

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

Для начала вспомним, для чего нам нужны плагины? Мой ответ — создание повторно используемого кода, и да — с удобным интерфейсом. Давайте напишем такой код, вот простая задачка: «По клику на параграф, текст должен измениться на красный»

Javascript и даже не jQuery

Дабы не забывать истоков — начнем с реализации на нативном javascript’е:

var loader = function () {
    // находим все параграфы
    var para = document.getElementsByTagName('P');
    // перебираем все, и вешаем обработчик
    for (var i=0,size=para.length;i<size;i++) {
        // обработчик
        para[i].onclick = function() {
             this.style.color = "#FF0000";
        }
    }
}
// естественно, весь код должен работать после загрузки всей страницы
document.addEventListener("DOMContentLoaded", loader, false);

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

jQuery, но еще не плагин

Теперь можно этот код упростить, подключаем jQuery и получаем следующий вариант:

$(document).ready(function(){
    $('p').click(function(){
        $(this).css('color', '#ff0000');
    })
});

Таки jQuery плагин

С поставленной задачей мы справились, но где тут повторное использование кода? Или если нам надо не в красный, а в зеленый перекрасить? Вот тут начинается самое интересное, чтобы написать простой плагин достаточно расширить объект $.fn:

$.fn.mySimplePlugin = function () {
    $(this).click(function(){
        $(this).css('color', '#ff0000');
    })
}

Если же писать более грамотно, то нам необходимо ограничить переменную $ только нашим плагином, а так же возвращать this, чтобы можно было использовать цепочки вызовов (т.н. chaining) , делается это следующим образом:

(function($) {
  $.fn.mySimplePlugin = function(){
     // код плагина ...
     return this;
  };
})(jQuery);

Внесу небольшое пояснение о происходящем, код (function($){…})(jQuery) создает анонимную функцию, и тут же вызывает ее, передавая в качестве параметра объект jQuery, таким образом внутри анонимной функции мы можем использовать алиас $ не боясь за конфликты с другими библиотеками — так как теперь $ находится лишь в области видимости нашей функции, и мы имеем полный контроль над ней

Добавим опцию по выбору цвета и получим рабочий плагин:

(function($) { 
    // значение по умолчанию - ЗЕЛЁНЫЙ
    var defaults = { color:'green' };
    
    // актуальные настройки, глобальные
    var options;
    
    $.fn.mySimplePlugin = function(params){
        // при многократном вызове функции настройки будут сохранятся, и замещаться при необходимости
        options = $.extend({}, defaults, options, params);
        
        $(this).click(function(){
            $(this).css('color', options.color);
        });

        return this;
    };
})(jQuery);

Вызов:

// первый вызов
$('p:first,p:last').mySimplePlugin();
// второй вызов
$('p:eq(1)').mySimplePlugin({ color: 'red' });

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

// актуальные настройки, будут индивидуальными при каждом запуске
var options = $.extend({}, defaults, params);

Работаем с коллекциями объектов

Тут все просто, достаточно запомнить — this содержит jQuery объект с коллекцией всех элементов, т.е. :

$.fn.mySimplePlugin = function(){
     console.log(this); // jQuery
     console.log(this.length); // число элементов
     return this;
};

Если мы хотим обрабатывать каждый элемент то соорудим следующую конструкцию:

// необходимо обработать каждый элемент в коллекции
return this.each(function(){
    $(this).click(function(){
        $(this).css('color', options.color);
    });
});

// предыдущий вариант немного избыточен,
// т.к. внутри функции click и так есть перебор элементов
return this.click(function(){
        $(this).css('color', options.color);
    });

Опять же напомню, если ваш плагин не должен что-то возвращать по вашей задумке — возвращайте this — цепочки вызовов в jQuery это часть магии, не стоит её ломать

Публичные методы

Так, у нас написан крутой плагин, надо бы ему еще докрутить функционала, пусть цвет регулируется несколькими кнопками на сайте. Для этого нам понадобится некий метод «color», который и будет в ответе за всё. Сейчас приведу пример кода готового плагина — будем курить вместе:

// значение по умолчанию
var defaults = { color:'green' };

// наши публичные методы
var methods = {
    // инициализация плагина
    init:function(params) {
        // актуальные настройки, будут индивидуальными при каждом запуске
        var options = $.extend({}, defaults, params);

        return this.click(function(){
           $(this).css('color', options.color);
        });
    },
    // изменение цвета
    color:function(color) {
        $(this).css('color', color);
    },
    // сброс цвета
    reset:function() {
        $(this).css('color', 'black');
    }
};

$.fn.mySimplePlugin = function(method){

    // немного магии
    if ( methods[method] ) {
        // если запрашиваемый метод существует, мы его вызываем
        // все параметры, кроме имени метода прийдут в метод
        // this так же перекочует в метод
        return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
        // если первым параметром идет объект, либо совсем пусто
        // выполняем метод init
        return methods.init.apply( this, arguments );
    } else {
        // если ничего не получилось
        $.error( 'Метод "' +  method + '" не найден в плагине jQuery.mySimplePlugin' );
    }
};

Теперь еще небольшой пример использование данных методов:

// вызов без параметров - будет вызван init
$('p').mySimplePlugin();
// вызов метода color и передача цвета в качестве параметров
$('p').mySimplePlugin('color', '#FFFF00');
// вызов метода reset
$('p').mySimplePlugin('reset');

Для понимания данного кусочка кода, вы должны разобраться лишь с переменной arguments, и с методом apply (тут им целые статьи посвятили — дерзайте)

О обработчиках событий

Если ваш плагин вешает какой-либо обработчик, то лучше всего (читай всегда) данный обработчик повесить в своём собственном namespace:

return this.bind("click.mySimplePlugin",function(){
    $(this).css('color', options.color);
});

Данный финт позволит в любой момент убрать все ваши обработчики, или вызвать только ваш, что очень удобно:

// вызовем лишь наш обработчик
$('p').trigger("click.mySimplePlugin");

// убираем все наши обработчики
$('p').unbind(".mySimplePlugin");

Использование data

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

// функция init
function() {
  var init = $(this).data('mySimplePlugin');

  if (init) {
    return this;
  } else {
    $(this).data('mySimplePlugin', true);
    return this.bind("click.mySimplePlugin",function(){
       $(this).css('color', options.color);
    });
  }
}

Источники

Цикл статей

  1. jQuery для начинающих
  2. jQuery для начинающих. Часть 2. JavaScript Меню
  3. jQuery для начинающих. Часть 3. AJAX
  4. jQuery для начинающих. Часть 4. Селекторы
  5. jQuery для начинающих. Часть 5. Эффекты
  6. jQuery для начинающих. Часть 6. События
  7. jQuery для начинающих. Часть 7. Пишем плагины
  8. jQuery для начинающих. Часть 8. Расширяем фильтры
  9. jQuery для начинающих. Часть 9. Пишем плагины анимации

© Антон Шевчук 2007-2016