Статьи

Вещи, которые я узнал, создавая плагин jQuery (часть I)

jQuery — одна из наиболее часто используемых библиотек JavaScript, если не самая популярная, которая позволяет создавать замечательные вещи с помощью большого набора небольших инструментов, предлагаемых веб-разработчикам: манипулирование HTML / DOM, манипулирование CSS, методы событий HTML, эффекты и анимации, AJAX, утилиты,…

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

Прежде чем начать

Из-за гибкости и мощи языка сообщество Perl гордится своим девизом Tim Today :

Есть несколько способов сделать это

Вы можете рассмотреть то же самое для JavaScript, это правда. Тот факт, что JavaScript — это не объектно-ориентированный язык, а язык, основанный на прототипах, позволяет следовать парадигме ООП разными способами. В поисках кода шаблона для создания плагина jQuery я обнаружил множество тонн, но не все придерживались тех же соглашений и идей.

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

Код

В дополнение к статье вы можете найти самодокументированную версию стандартного кода в моем репозитории GitHub .

Когда начать

Если вы планируете создать плагин jQuery, первое, что я предлагаю вам начать читать, это раздел « Плагины / авторинг » проектной документации. Это отличный стартовый ресурс, но в реальной жизни вы скоро обнаружите, что вам нужно знать немного больше об этом.


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

Предположим, у нас есть плагин jQuery beautyLink, который преобразует обычную ссылку ( <a>элемент) в действительно приятную, изменяя семейство шрифтов, текст и цвет фона. Поэтому мы должны включить его в нашу страницу, прежде чем начать его использовать:

<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery-beautylink.js"></script>

Обычный способ создать и применить его к элементу:

$('#linkID').beautyLink();

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

$('a').beautyLink();

Позже, чтобы изменить цвет текста на красный, мы могли бы вызвать открытый метод плагина, например:

$('#linkID').beautyLink('color', 'red');

или чтобы получить текущий цвет текста:

$('#linkID').beautyLink('color');

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

Создание нового плагина

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

Когда мы включаем файл JavaScript в веб-страницу, нам нужно, чтобы код выполнялся автоматически, чтобы плагин мог быть зарегистрирован в jQuery. Для этого весь код JavaScript в файле должен быть внутри кода:

(function($, window, document, undefined) {
  // The code here
})(jQuery, window, document);

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

Функция обертки

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

jQuery.fn.myPlugin = function(options) {
  // Do your awesome plugin stuff here
};

или же

jQuery.fn['myPlugin'] = function(options) {
  // Do your awesome plugin stuff here
};

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

Как отличить действие?

Вопрос в том, как мы реализуем функцию-обертку плагина, чтобы различать, должна ли она инициализировать плагин или вызвать метод? Ответ в optionsпараметре.

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

$('#linkID').beautyLink();

Если мы создаем экземпляр любого аргумента, optionsпараметром является Object:

$('#linkID').beautyLink({
  someOption: 'a',
  someOther: 123
});

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

$('#linkID').beautyLink('color', 'red');

тогда optionsпараметр является массивом с двумя элементами['color', 'red']

Стартовый код для функции оболочки

Учитывая вышесказанное, мы можем написать базовый код для функции-оболочки:

$.fn[pluginName] = function(options) {
    var args = arguments;

    if (options === undefined || typeof options === 'object') {
        // Creates a new plugin instance

    } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
        // Call a public pluguin method (not starting with an underscore) and different
        // from the 'init' one

    }
};

Цепной или не цепной

jQuery известен (и мощен) своим цепным способом работы, то есть вызов метода возвращает ссылку на тот же элемент, поэтому мы можем сделать другой вызов. Например:

$('#someID')
  .parents(".pane")
  .animate({ opacity: "hide" }, "slow");

или применяется к нашему плагину:

$('#linkID')
  .beautyLink('color', 'red')
  .beautyLink('backgroundColor', 'black');

Мы должны думать, какие из наших методов должны быть цепными, а какие нет. Например, методы-получатели должны нарушать цепочечность . В нашем случае мы хотим позвонить:

$('#linkID').beautyLink('color');

возвращает redзначение, а не ссылку на элемент, чтобы сделать еще один вызов.

Реализация цепочки

Когда $.fn[pluginName]вызывается функция-обертка, эта ссылка указывает на:

  • выбранный элемент DOM, как при использовании:
    $('#linkID').beautyLink('color', 'red');

    или же

  • список выбранных элементов DOM, например, при использовании:
    $('a').beautyLink('color', 'red');

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

$.fn[pluginName] = function(options) {
    return this.each(function() {
        new Plugin(this, options);
    });
}

Как избежать цепочечности

Решение о том, как избежать цепочки методов, легко, просто не пишет this.each()и не выполняет код при первом появлении, то есть this[0].

Это будет более понятно в окончательном коде.

Функция jQuery.data ()

Мы используем $.data()функцию в нашем коде, поэтому требуется краткое объяснение. Функция позволяет хранить произвольные данные на элементе (или получить это значение).
$.data()

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

Код функции оболочки оболочки

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

  • Если плагин вызывается без аргументов, то плагин инициализируется и ссылка сохраняется в элементе DOM.
  • Если вызывается метод плагина и он не является методом получения, то метод называется поддержанием цепочки.
  • Если вызывается метод плагина, и он является методом получения, тогда мы возвращаем значение и нарушаем цепочечность.
    $.fn[pluginName] = function(options) {
        var args = arguments;
    
        if (options === undefined || typeof options === 'object') {
            // Creates a new plugin instance, for each selected element, and
            // stores a reference withint the element's data
            return this.each(function() {
                if (!$.data(this, 'plugin_' + pluginName)) {
                    $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
                }
            });
        } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
            // Call a public pluguin method (not starting with an underscore) for each 
            // selected element.
            if (Array.prototype.slice.call(args, 1).length == 0 && $.inArray(options, $.fn[pluginName].getters) != -1) {
                // If the user does not pass any arguments and the method allows to
                // work as a getter then break the chainability so we can return a value
                // instead the element reference.
                var instance = $.data(this[0], 'plugin_' + pluginName);
                return instance[options].apply(instance, Array.prototype.slice.call(args, 1));
            } else {
                // Invoke the speficied method on each selected element
                return this.each(function() {
                    var instance = $.data(this, 'plugin_' + pluginName);
                    if (instance instanceof Plugin && typeof instance[options] === 'function') {
                        instance[options].apply(instance, Array.prototype.slice.call(args, 1));
                    }
                });
            }
        }
    };

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

$.fn[pluginName].getters = ['someGetterMethod'];

Продолжение следует…

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