Пишем свой первый плагин на jQuery. jQuery Fancy капча для формы регистрации

С момента появления jQuery прошло почти 10 лет и на сегодняшний день это самая популярная JavaScript-библиотека. Десять лет назад доступ в интернет был возможен через ограниченное число браузеров, спроектированных таким образом, чтобы свести к минимуму возможность манипулирования HTML DOM (Document Object Model). JQuery оказался палочкой-выручалочкой для многих разработчиков, стремившихся к одинаковому отображению содержимого сайтов во всех существующих браузерах. Развивавшие jQuery энтузиасты стремились объединить возможности браузеров и таким образом создать общий для всех интерфейс, который будет работать независимо от типа и версии браузера. Основная заслуга разработчиков состоит в том, что они создали новые интерфейсы API, которые были лучше «родных» браузерных и реализовали функции, которые не поддерживались программным интерфейсом браузера. Однако некоторые разработчики не склоны переоценивать роль jQuery в решении проблем кроссбраузерности и настаивают на том, что библиотека стала столь популярной благодаря реализации querySelectors. Как обычно, истина где-то посередине.

На сегодняшний день браузерная экосистема является не такой сложной, как это было 10 лет назад. Несмотря на то, что некоторые браузеры не могут реализовать все, что предлагает HTML5 API, все же у разработчиков в наше время гораздо меньше проблем с кроссбраузерностью и реализацией различных функций. Если сегодня что-то отлично работает в Chrome, то, вероятно, это также будет работать в Firefox или Edge. Основные элементы JavaScript наряду с querySelectors хорошо задокументированы и поддерживаются всеми производителями браузеров. Поэтому на первый взгляд может показаться, что те проблемы, которые решает jQuery, более таковыми не являются. Чистый JavaScript всегда будет быстрее, чем решение с использованием библиотеки, так что возникает вопрос: а нужно ли сегодня использовать технологию, которая в какой-то мере уже устарела? Цикл CPU является товаром, а время нет. Будет ли экономия 30 кБ оправданной, если придется писать код, тестировать его, если уже есть готовое решение?

Все это вопрос выбора. Кто-то стремится к совершенному коду, кто-то использует фрагменты кода, созданные другими разработчиками. Библиотека jQuery насчитывает тысячи отлично работающих и хорошо задокументированных плагинов, которые повышают производительность и позволяют реализовывать самые смелые идеи. Многие из этих плагинов к тому же совершенно бесплатны. Предлагаем вашему вниманию 10 лучших jQuery-плагинов, которые активно поддерживаются и регулярно обновляются их создателями.

Firewall это очень интересный кроссбраузерный jQuery-плагин, предназначенный для работы с макетами на основе модульной сетки. Он позволяет создавать впечатляющие анимационные эффекты с использованием возможностей SCC3 и хорошо работает с call back events. Если нужно создавать гибкие макеты с множеством изображений типа Pinterest, то Firewall является наилучшим решением для создания динамических сеток. Freewall работает практически во всех современных браузерах и даже в древнем IE8, что делает этот плагин действительно универсальным инструментом.

Плагин multiscroll.js позволяет добавить на сайт разнонаправленную прокрутку основных элементов дизайна. Это облегчает создание мультипрокрутки для сайтов с двумя колонками или панелями. Основное назначение плагина заключается в привлечении внимания пользователя к главному контенту без ущерба для UX. Плагин отлично работает как на современных, так и на устаревших браузерах и, конечно, в мобильной среде.

RowGrid.js – это простенький плагин, которые позволяет расположить изображения на сайте ровными рядами, точно так же, как это сделано в поиске по изображениям Google. Это модно, красиво и не слишком навязчиво. RowGrid.js расставляет изображения в рядах, ориентируясь на размер родительского элемента: он подбирает картинки таким образом, чтобы они гармонично смотрелись в пределах установленных границ, при этом некоторые элементы подвергаются масштабированию. Однако при работе с этим плагином нужно помнить, что все изображения должны быть одинаковыми по высоте, иначе плагин не будет работать и красивой произвольной сетки не получится.

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

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

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

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

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

Плагин Flickity отличается очень подробной документацией. Весь функционал понятно описан и логически структурирован. Это один из самых «отшлифованных» jQuery-плагинов для реализации эффекта карусели. При помощи Flickity создание отзывчивых слайдеров превращается в легкую работу, так как в плагине есть все инструменты для реализации любой идеи. Плагин условно бесплатный, для использования в коммерческих проектах придется приобрести платную версию.

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

Дополните библиотеку jQuery своим собственным кодом

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

Плагины jQuery позволяют пополнять библиотеку jQuery своим кодом; их можно использовать для любых повторяющихся функций. Например, имеется множество плагинов для демонстрации слайд-шоу и создания раскрывающегося списка или меню "аккордеон". Если поискать плагины jQuery, то можно найти множество примеров, которые можно использовать в собственных проектах (и посмотреть, как они построены).

Часто используемые сокращения

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

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

jQuery ― это библиотека, которая расширяет язык JavaScript. Создавая новый плагин, вы, по существу, расширяете библиотеку jQuery, которая, в свою очередь, расширяет JavaScript. Чтобы понять, как именно ваш плагин расширяет библиотеку jQuery, требуется понимание свойства JavaScript prototype . Это свойство используется не явно, а скрыто ― через свойство jQuery fn , которое представляет собой jQuery- псевдоним собственного свойства prototype JavaScript.

Чтобы создать новый jQuery-плагин, используя свойство fn , достаточно присвоить его имя свойству fn и указать ему на новую функцию, которая будет выступать в качестве функции-конструктора, как в обычном JavaScript. Код, приведенный в листинге 1, показывает, как определить новый jQuery-плагин с именем accordion с помощью объекта jQuery и свойства fn , а затем присвоить ему новую функцию конструктора.

Листинг 1. Определение нового jQuery-плагина с именем accordion jQuery.fn.accordion = function() { // Добавить здесь код плагина };

В листинге 1 показан один из способов создания jQuery-плагина; в этом примере нет ничего функционально неправильного. Однако рекомендуется сначала создать функцию-оболочку, которая позволит использовать знак доллара ($). По умолчанию знак доллара может вызвать конфликты с другими структурами JavaScript. Если же упаковать плагин в функцию, конфликтов не будет, и знак доллара можно использовать. Пример кода, приведенный в листинге 2, демонстрирует, как применить функцию-оболочку к определению jQuery-плагина.

Листинг 2. Упаковка нового jQuery-плагина с именем accordion в функцию-оболочку (function($) { $.fn.accordion = function() { // Добавить здесь код плагина }; })(jQuery);

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

Сохранение chainability

Преимуществом jQuery является возможность использовать любой тип селектора. Однако нужно иметь в виду, что ваш плагин может работать с несколькими различными типами элементов. Используя ключевое слово this , можно применять связанные функции, обращаясь к каждому элементу в цикле, независимо от типа этого элемента. Если ключевое слово return предшествует циклу each , то можно сохранить свойство chainability своего плагина. В листинге 3 показан цикл each , назначенный обработчику функции и скомбинированный с ключевым словом return .

Листинг 3. Использование ключевого слова return перед циклом each (function($) { $.fn.accordion = function() { return this.each(function() { // Использование return позволяет сохранить chainability }); }; })(jQuery);

Благодаря коду, приведенному в листинге 3, пример плагина accordion можно использовать в цепочке вызовов методов. Chainability — еще одна важная особенность jQuery — позволяет использовать плагин в цепочке вызовов методов. Например, следующий код показывает, как HTML-элемент постепенно гасится, а затем удаляется из объектной модели документов (DOM) в одной цепочке вызовов методов.

$("#my-div").fadeOut().remove(); Структурирование "аккордеона"

Типичная конструкция "аккордеон" включает в себя строки заголовков и смежные с ними области с некоторым содержимым. "Аккордеоны" отлично подходят для HTML-структуры определения списков; для заголовков используются элементы dt , а для областей содержимого ― элементы dd . Структура HTML из листинга 4 представляет собой определение списка с четырьмя заголовками и соответствующими областями содержимого.

Листинг 4. Одна цепочка вызовов методов Section 1 Section 2 Section 3 Section 4

В определении списка из листинга 4 также имеется класс CSS с присвоенным ему именем accordion . Без всяких CSS эта структура "аккордеон" соответствует неформатированной структуре с рисунка 1.

Рисунок 1. Структура "аккордеон" без CSS

Класс accordion используется для применения стилей к общему определению списка, заголовкам и области содержимого. В примере, приведенном в листинге 5, в самом классе accordion указаны ширина, границы, шрифт и размер шрифта. Любой из примеров применения CSS можно изменить, выбрав свои собственные стили, такие как цвет, шрифт, размеры и интервалы.

Листинг 5. Класс CSS accordion, используемый для задания стилей общего определения списка .accordion { width: 500px; border: 1px solid #ccc; border-bottom: none; font-family: Arial, Helvetica, sans-serif; font-size: 12px; }

Затем класс CSS accordion используется для определения стилей заголовков (dt) и содержимого dd . И заголовки, и содержимое содержат общие стили, которые определяют нижнюю границу и задают значение полей 0, что позволяет областям заголовков и содержимого располагаться впритык друг к другу, как показано в листинге 6.

Листинг 6. Общие стили заголовков и областей содержимого "аккордеон" .accordion dt, .accordion dd { border-bottom: 1px solid #ccc; margin: 0px; }

Чтобы элемент dt был больше похож на заголовок, зададим цвет фона и добавим указатель курсора, чтобы создать впечатление активного заголовка. В этом классе есть и другие стили, такие как отбивка или размер и плотность шрифта. Элемент dd добавляет отбивку, чтобы отделить описание от заголовка. Пример приведен в листинге 7.

Листинг 7. Стили CSS для заголовков и областей содержимого "аккордеон" .accordion dt { background: #eaeaea; cursor: pointer; padding: 8px 4px; font-size: 13px; font-weight: bold; } .accordion dd { padding: 12px 8px; }

Когда все классы CSS добавлены, визуальный результат больше напоминает аккордеон, как показано на рисунке 2.

Рисунок 2. Структура "аккордеон" с применением CSS
Программирование плагина

Чтобы сделать аккордеон функциональным, необходимо написать код функций jQuery-плагина, который мы начали создавать в предыдущем разделе. Плагин accordion начинается с циклического считывания всех определенных "клавиш аккордеона". Для определения "аккордеона" используется следующий вызов jQuery в пределах HTML-документа или во внешнем внедренном файле JavaScript.

$("dl#my-accordion").accordion();

Для каждой "клавиши" вызываются соответствующие определения с помощью метода jQuery children , который возвращает массив элементов dt . Применим событие click к элементам dt , а затем к каждому dt ― метод с именем reset . Метод reset позволяет свернуть все элементы dd при первой загрузке accordion. Событие click вызывает специальный метод с именем onClick при нажатии на элемент dt или заголовок. Метод onClick выполняет поиск всех элементов dt в "аккордеоне". Он вызывает специальный метод hide , который скрывает каждый соответствующий элемент dd с помощью метода next для поиска элемента dd , смежного с элементом dt , а затем сдвигает его вверх для анимации процесса закрытия.

Когда все элементы dd скрыты, элемент dd , связанный с нажатым элементом dt , становится видимым благодаря методу slideDown и создает анимацию расширения и сжатия, как показано в листинге 8. Последняя строка кода в методе onClick - это строка return false , которая гарантирует, что никакой нажатый заголовок не будет проявлять свое обычное поведение. Например, при использовании элемента anchor в качестве заголовка понадобится метод return false , чтобы пользователь не попал на другую страницу или в другую часть существующей страницы.

Листинг 8. Специальные функции accordion, используемые для создания jQuery-плагина (function($) { $.fn.accordion = function(options) { return this.each(function() { var dts = $(this).children("dt"); dts.click(onClick); dts.each(reset); }); function onClick() { $(this).siblings("dt").each(hide); $(this).next().slideDown("fast"); return false; } function hide() { $(this).next().slideUp("fast"); } function reset() { $(this).next().hide(); } } })(jQuery);

Если плагин accordion связан со структурой списка HTML-определений, как тот, что мы создали ранее, будет применяться функция accordion. В функциях accordion при нажатии на один заголовок или элемент dt открывается соответствующая область содержимого, а любые другие открытые области содержимого закрываются. Иными словами, в каждый момент времени может быть открыта только одна область содержимого.

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

Плагин JQuery может содержать значения по умолчанию и параметры настройки. Параметры настройки ― это, по существу, те аргументы, которые передаются плагину. Вместо передачи нескольких аргументов с параметрами настройки можно передать один аргумент в качестве литерала объекта, что является стандартным приемом для jQuery. Если в плагине разрешены параметры, то следует указать для них значения по умолчанию с помощью объекта defaults . Как и параметры, значения по умолчанию представляют собой литерал объекта, который должен содержать свойства, передаваемые в плагин.

Например, если допускается свойство, которое можно использовать для открытия первой области содержимого "аккордеона" при его первой загрузке, то в плагине следует указать значение по умолчанию для этого свойства. Используйте значения по умолчанию для определения состояния функций по умолчанию, а параметры настройки ― для переопределения значений по умолчанию. Когда плагин получает параметры, для фактического переопределения можно использовать метод $.extend . Метод $.extend jQuery объединяет два или более объектов. Пример, приведенный в листинге 9, демонстрирует обычную практику использования метода $.extend для соединения определяемых пользователем параметров со значениями по умолчанию в плагине jQuery.

Листинг 9. Добавление параметров настройки и значений по умолчанию в плагин jQuery (function($) { $.fn.accordion = function(options) { var settings = $.extend({}, {open: false}, options); return this.each(function() { var dts = $(this).children("dt"); dts.click(onClick); dts.each(reset); if(settings.open) $(this).children("dt:first-child").next().show(); }); function onClick() { $(this).siblings("dt").each(hide); $(this).next().slideDown("fast"); return false; } function hide() { $(this).next().slideUp("fast"); } function reset() { $(this).next().hide(); } } })(jQuery);

Аргументами метода $.extend служат целевой объект и два или более объектов, подлежащих объединению. В этом примере целевым объектом является пустой литерал объекта, который служит контейнером для объединяемых объектов. Цель становится единым объектом, который содержит значения объединяемых объектов ― в данном случае переменной settings . Второй аргумент ― это литерал объекта, содержащий свойства плагина по умолчанию. Третий аргумент ― определяемые пользователем параметры настройки. Чтобы передать параметры настройки с помощью плагина accordion в HTML-элементе, нужно знать, какие свойства плагин исключает, чтобы их можно было передать в виде литерала объекта, как показано ниже.

$("dl#my-accordion").accordion({open:true});

В примере, приведенном в листинге 9, параметры, передаваемые плагину, переопределяют значения по умолчанию с помощью метода $.extend . Если никакие параметры не передаются, используются значения по умолчанию. В примере плагина свойство open используется для определения того, должна ли при его загрузке открываться первая область содержимого.

Возможность многократного использования

Пример плагина accordion можно многократно использовать в любом HTML-документе, в том числе в одном и том же. Используя новый созданный нами плагин accordion, можно включить несколько таких структур "аккордеон" и определить каждую из них отдельно как jQuery accordion. Чтобы добавить в HTML-документ несколько "аккордеонов", просто добавьте нужное количество структур accordion. Код, приведенный в листинге 10, включает две структуры accordion, разделенных знаком конца абзаца.

Листинг 10. Использование нескольких "аккордеонов" в пределах одного и того же документа HTML Section 1 Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Section 2 Vestibulum a velit eu ante scelerisque vulputate. Section 3 Nam mi. Proin viverra leo ut odio. Curabitur malesuada. Section 4 Vivamus nisi metus, molestie vel, gravida in, condimentum sit amet, nunc. Section 1 Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Section 2 Vestibulum a velit eu ante scelerisque vulputate.

Две структуры accordion в листинге 10 почти идентичны, не считая их содержания и, что еще важнее, значений их идентификаторов. Первая структура содержит значение идентификатора my-accordion . Вторая структура содержит значение идентификатора my-accordion2 . Теперь к этим структурам можно обращаться независимо друг от друга. Например, следующий сценарий jQuery определяет каждую структуру "аккордеон" с использованием нового созданного нами плагина.

$("dl#my-accordion").accordion({open:true}); $("dl#my-accordion2").accordion({open:true});

Обе структуры "аккордеон" определяются с открытой первой панелью по умолчанию. На рисунке 3 приведен пример использования нескольких плагинов accordion в одном и том же HTML-документе.

Рисунок 3. Несколько структур "аккордеон" в одном и том же HTML-документе
Собираем все вместе

Создав новый специальный jQuery-плагин accordion, написав CSS и разместив разметку HTML, можно собрать все это вместе на окончательной Web-странице. Чтобы jQuery-плагин accordion работал, необходимо внедрить библиотеку jQuery. Я предпочитаю использовать сеть доставки контента (CDN), которая доставляет библиотеки в зависимости от географического положения пользователя и поэтому обеспечивает максимально возможную скорость загрузки файла. Библиотека jQuery есть в CDN Google, и этот файл можно внедрить на Web-страницу, воспользовавшись URL https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js .

Имеются и другие версии библиотеки. См. ссылки в разделе на библиотеки на сайте Google для разработчиков. Единственные дополнительные файлы, которые нужно указать в HTML-документе, это файл CSS, который определяет стили "аккордеона", и jQuery-плагин accordion. После этого HTML-разметка фактических структур "аккордеон" изменится. Пример приведен в листинге 11.

Листинг 11. Определение двух структур "аккордеон" как jQuery-аккордеонов Creating a Custom jQuery Plugin $(document).ready(function() { $("dl#my-accordion").accordion({open:true}); $("dl#my-accordion2").accordion({open:true}); }); Section 1 Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Section 2 Vestibulum a velit eu ante scelerisque vulputate. Section 3 Nam mi. Proin viverra leo ut odio. Curabitur malesuada. Section 4 Vivamus nisi metus, molestie vel, gravida in, condimentum sit amet, nunc.

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Section 1 Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Section 2 Vestibulum a velit eu ante scelerisque vulputate. Заключение

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

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

Итак, вы уже разобрались с jQuery и теперь хотели бы научиться писать собственные плагины. Отлично! Вы пришли в правильное место. Расширение возможностей jQuery с помощью плагинов и методов - это очень мощный механизм, который сэкономит вам и вашим коллегам не один час разработки. Эта статья описывает базовые моменты, рекомендации и распространённые ошибки, которые случаются при написании плагина.

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

Начните писать jQuery-плагин с добавления новой функции-свойства к объекту jQuery.fn . Название функции и будет названием вашего плагина:

JQuery.fn.myPlugin = function() { // Творить волшебство здесь };

Но постойте! Где же чудный значок доллара, к которому я так привык? Он есть, но чтобы убедиться, что ваш плагин не будет конфликтовать с другими библиотеками, которые тоже могут использовать знак доллара, будет лучше сделать так. Передадим объект jQuery в самовызывающуюся функцию (замыкание), которая привяжет его к знаку доллара, так что никакая другая библиотека не сможет его переопределить в текущем scopе"е исполнения.

(function($){ $.fn.myPlugin = function() { // Творить волшебство здесь }; })(jQuery);

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

Контекст

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

(function($){ $.fn.myPlugin = function() { // нет необходимости делать $(this), потому что // "this" уже является jQuery-объектом // $(this) - это тоже самое, что и $($("#element")); this.fadeIn("normal", function() { // this - элемент DOM }); }; })(jQuery); $("#element").myPlugin();

Основы

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

(function($){ $.fn.maxHeight = function() { var max = 0; this.each(function() { max = Math.max(max, $(this).height()); }); return max; }; })(jQuery); var tallest = $("div").maxHeight(); // Возвращает высоту самого высокого div"а

Этот простой плагин возвращает высоту самого высокого div "а на странице, используя метод .height() .

Цепочки вызовов

Предыдущий пример возвращает высоту самого высокого div "а на странице, но зачастую задача плагина не вернуть определённое значение, а модифицировать каким-то образом набор элементов, и передать их дальше, следующему методу в цепочке. В этом красота разработки с использованием jQuery и это одна из причин, почему jQuery так популярен. Чтобы цепочки вызовов работали с вашим плагином, вы должны убедиться, что он возвращает this .

(function($){ $.fn.lockDimensions = function(type) { return this.each(function() { var $this = $(this); if (!type || type == "width") { $this.width($this.width()); } if (!type || type == "height") { $this.height($this.height()); } }); }; })(jQuery); $("div").lockDimensions("width").css("color", "red");

Благодаря тому, что плагин возвращает this , работают цепочки вызовов и jQuery-коллекция может быть передана следующему методу jQuery, например методу .css . Так что, если ваш плагин не должен возвращать какое-то значение, вам всегда следует возвращать this . Кроме того, как вы уже могли заметить, передаваемые в вызове плагина аргументы попадают в текущий scope функции-плагина. Так в предыдущем примере строка "width" становится аргументом type внутри функции-плагина.

Опции и значения по умолчанию

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

(function($){ $.fn.tooltip = function(options) { var settings = { "location" : "top", "background-color" : "blue" }; return this.each(function() { // Если опции существуют, давайте объединим из с нашими значениями по умолчанию if (options) { $.extend(settings, options); } // Здесь идёт код плагина tooltip }); }; })(jQuery); $("div").tooltip({ "location" : "left" });

В этом примере, после вызова плагина tooltip с заданными параметрами, значение для параметра location переписывается и становится равным "left" , а значение background-color остаётся как и было "blue" . Итоговый объект с параметрами будет выглядеть так:

{ "location" : "left", "background-color" : "blue" }

Значения по умолчанию - это отличный способ предоставить максимальную гибкость настройки плагина без необходимости указывать все параметры сразу.

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

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

Методы

Ни при каких обстоятельствах плагин не должен использовать больше одного пространства имён в объекте jQuery.fn .

(function($){ $.fn.tooltip = function(options) { // ТАК }; $.fn.tooltipShow = function() { // ДЕЛАТЬ }; $.fn.tooltipHide = function() { // НЕЛЬЗЯ }; $.fn.tooltipUpdate = function(content) { // !!! }; })(jQuery);

Такой подход создаёт беспорядок в пространствах имён $.fn . Чтобы этого избежать, соберите все методы вашего плагина в один объект и вызывайте их путем передачи плагину названия нужного метода в качестве параметра.

(function($){ var methods = { init: function(options) { // ТАК }, show: function() { // ДЕЛАТЬ }, hide: function() { // ПРАВИЛЬНО }, update: function(content) { // !!! } }; $.fn.tooltip = function(method) { // Логика вызова метода if (methods) { return methods[ method ].apply(this, Array.prototype.slice.call(arguments, 1)); } else if (typeof method === "object" || ! method) { return methods.init.apply(this, arguments); } else { $.error("Метод " + method + " не существует в jQuery.tooltip"); } }; })(jQuery); $("div").tooltip(); // вызов метода init $("div").tooltip({ // вызов метода init foo: "bar" }); $("div").tooltip("hide"); // вызов метода hide $("div").tooltip("update", "Это новый контент тултипа!"); // вызов метода update

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

События

У метода bind есть возможность, о которой мало кто знает, - использование пространств имён для привязки обработчиков событий. Если ваш плагин обрабатывает события, то было бы неплохо для обработчиков указать своё пространство имён. Тогда, если понадобится отвязать эти обработчики от событий, то вы сможете легко это сделать не затрагивая другие обработчики тех же событий. Чтобы назначить пространство имён нужно дописать.namespace к типу привязываемого события.

(function($){ var methods = { init: function(options) { return this.each(function(){ $(window).bind("resize.tooltip", methods.reposition); }); }, destroy: function() { return this.each(function(){ $(window).unbind(".tooltip"); }) }, reposition: function() { // ... }, show: function() { // ... }, hide: function() { // ... }, update: function(content) { // ... } }; $.fn.tooltip = function(method) { if (methods) { return methods.apply(this, Array.prototype.slice.call(arguments, 1)); } else if (typeof method === "object" || ! method) { return methods.init.apply(this, arguments); } else { $.error("Метод " + method + " не существует в jQuery.tooltip"); } }; })(jQuery); $("#fun").tooltip(); // А потом... $("#fun").tooltip("destroy");

В этом примере, при инициализации плагина tooltip, происходит привязка обработчика reposition к событию resize объекта window с использованием пространства имён tooltip. Если потом понадобится отключить плагин, то отвязать привязанные им события можно будет передав методу unbind название пространства имён, в нашем случае - "tooltip". Таким образом можно отвязывать обработчики событий, привязанные плагином, не опасаясь случайно отвязать чужие.

Данные

Зачастую, при разработке плагинов, требуется сохранять состояния или проверять, был ли ваш плагин инициализирован на конкретном DOM-элементе. Удобный способ следить за переменными на уровне отдельных элементов - использование метода jQuery data . Но, вместо того, чтобы следить за кучей отдельных data -вызовов с разными именами, лучше сохранить все ваши переменные в один объект, используя его как пространство имён, и делать data -вызов к нему.

(function($){ var methods = { init: function(options) { return this.each(function(){ var $this = $(this), data = $this.data("tooltip"), tooltip = $("", { text: $this.attr("title") }); // Если плагин еще не был инициализирован if (! data) { /* Здесь делаем еще какие-то вещи */ $(this).data("tooltip", { target: $this, tooltip: tooltip }); } }); }, destroy: function() { return this.each(function(){ var $this = $(this), data = $this.data("tooltip"); // Используем пространства имён FTW $(window).unbind(".tooltip"); data.tooltip.remove(); $this.removeData("tooltip"); }) }, reposition: function() { // ... }, show: function() { // ... }, hide: function() { // ... }, update: function(content) { // ... } }; $.fn.tooltip = function(method) { if (methods) { return methods.apply(this, Array.prototype.slice.call(arguments, 1)); } else if (typeof method === "object" || ! method) { return methods.init.apply(this, arguments); } else { $.error("Метод " + method + " не существует в jQuery.tooltip"); } }; })(jQuery);

Использование data помогает вам следить за переменными и состояниями между вызовами методов плагина. Хранение всех данных в одном объекте позволяет легко к ним обращаться, и, в случае необходимости, так же легко их удалять.

Написание jQuery-плагинов позволяет наиболее эффективно использовать возможности библиотеки. А повторное использование кода экономит ваше время и делает разработку более эффективной. Вот краткие итоги поста, держите их в уме, когда будите писать свой следующий плагин:

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

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

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

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

Плагин представляет собой новый метод в объекте jquery, следственно, для создания плагина, необходимо добавить функцию с его реализацией в объект jQuery.fn, как это показано ниже.

(function($){ jQuery.fn.mySimpleSlider = function(options){ // Здесь будет реализация метода }; })(jQuery);

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

Options = $.extend({ nextBtn:null, // Селектор кнопки "следующий" prevBtn:null, // Селектор кнопки "предыдущий" playBtn:null, // Селектор кнопки play/pause selectors:null, // Селектор "переключателей" slideWidth:100, // Шаг прокрутки (px) delay:null, // Интервал между авто пролистыванием duration:500 // Скорость переключения слайдов }, options);

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

Var slider = this; // Объект, к которому применен плагин var intervalID; // Указатель таймера

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

// Функция «включения» function start(){ // Вызов функции next при нажатии на nextBtn $(options.nextBtn).on("click", next); // Вызов функции prev при нажатии на prevBtn $(options.prevBtn).on("click", prev); Запуск таймера для авто пролистывания setTimer(); /* Перелистывание на выбранный слайд при условии существования переключателей */ if(options.selectors) { $(options.selectors).on("click", function(){ selectSlide($(this).index()) }); } } // Функция «выключения» function finish(){ // Отключение вызова функций всех событий $(options.nextBtn).unbind(); $(options.prevBtn).unbind(); $(options.selectors).unbind(); // Остановка таймера авто переключения clearInterval(intervalID); }

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

Function setTimer(){ // Если задержка не задана - не запускаем таймер if(!options.delay) return false; /* Если задана кнопка play/pause И она в состоянии "pause" - не запускаем таймер */ if(options.playBtn) if($(options.playBtn).hasClass("pause")) return false; // Запуск таймера intervalID = setInterval(next, options.delay); }

Function next(){ /* Если текущий слайд - последний, то возвращаемся к первому */ if(getIndex() == (getCount()-1)) { selectSlide(0); } // Иначе идет перелистывание на следующий слайд else { selectSlide(getIndex()+1); } } function prev(){ /* Если текущий слайд - первый, то переходим к последнему */ if(getIndex() == 0) { selectSlide(getCount()-1); } // Иначе происходит переход на предыдущий слайд else { selectSlide(getIndex()-1); } }

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

// Функция переключения на слайд //с выбранным индексом function selectSlide(index){ // Отключение срабатывания событий finish(); // Переключение на слайд $(slider).children("ul").animate({left:options.slideWidth *-1*index+"px"}, options.duration, start); // Отображение выбранного слайда в «статус баре» $(options.selectors).removeClass("active"); $(options.selectors).eq(index).addClass("active"); } // Функция, которая возвращает индекс текущего слайда function getIndex(){ return ($(slider).children("ul") .position().left / options.slideWidth)*(-1); } // Функция подсчета количества слайдов function getCount(){ return $(slider).children("ul") .children("li").length; }

Завершает наш плагин функция make , которая и запускается при вызове плагина. Она будет содержать функцию включения события, а так же код запускающий работу кнопки play/pause если такая имеется. Этот код не занесен в функцию start так как используется только один раз, при запуске плагина. Кнопка имеет два состояния: play и pause , которые контролируются через классы с соответствующими названиями. Функция make имеет следующий вид:

Var make = function(){ // Если задана кнопка play/pause if(options.playBtn) { /* При нажатии на кнопку меняем ее состояние на обратное текущему и запускаем либо останавливаем таймер в зависимости от состояния кнопки */ $(options.playBtn).on("click", function(){ if($(this).hasClass("pause")) { $(this).removeClass("pause"); $(this).addClass("play"); setTimer(); } else { clearInterval(intervalID); $(this).removeClass("play"); $(this).addClass("pause"); } }); } // Включение реакции на события // управляющих элементов start(); };

По завершению работы плагин возвращает функцию make :

Return this.each(make);

На этом наш урок по созданию собственных плагинов окончен. Удачной реализации собственных идей и до свидания!

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

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

Начнем писать JQuery плагин, с добавления нового метода к объекту jQuery.fn, где имя метода - это название Вашего плагина:

JQuery.fn.myPlugin = function() { // здесь помещаете код Вашего плагина };

Но постойте! Где же мой знак доллара, который я знаю и люблю?- спросите Вы. Он по прежнему доступен, однако надо убедиться, что Ваш плагин не будет конфликтовать с другими библиотеками, которые также могут использовать знак доллара(Mootools, Prototype). Для этого код Вашего плагина нужно поместить в само вызывающееся замыкание.

(function($){ $.fn.myPlugin = function() { // здесь код Вашего плагина }; })(jQuery);

Так-то лучше. После этого, другие библиотеки сколько угодно могут изменять знак $, на Вас это не отразится. Внутри замыкания, $ будет равен jQuery.

Контекст

Теперь у нас есть оболочка, и мы можем начать писать фактический код плагина. Но прежде, чем мы это сделаем, я хотел бы сказать несколько слов о контексте. Внутри плагина зарезервированное слово this это ссылка на объект jQuery. Но когда, в коде плагина используются callback функции, то там this - это ссылка на нативный DOM элемент. Ошибки возникают тогда, когда разработчики лишний раз делают $(this) или наоборот забывают это делать

(function($){ $.fn.myPlugin = function() { // тут не нужно делать так $(this) потому-что // "this" уже является объектом jquery // $(this) будет обозначать то же самое, что $($("#element")); this.fadeIn("normal", function(){ // а вот здесь this это ссылка на нативный DOM объект, и чтобы работать с ним // надо сделать так $(this) }); }; })(jQuery); $("#element").myPlugin();

Hello World!!!

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

(function($){ $.fn.maxHeight = function() { var max = 0; this.each(function() { max = Math.max(max, $(this).height()); }); return max; }; })(jQuery); var tallest = $("div").maxHeight(); // вернет высоту самого высокого div"а

Это простой плагин, который использует метод .height() для возвращения высоты самого высокого DIV"а на странице.

Поддержка цепочек вызовов

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

(function($){ $.fn.lockDimensions = function(type) { return this.each(function() { var $this = $(this); if (!type || type == "width") { $this.width($this.width()); } if (!type || type == "height") { $this.height($this.height()); } }); }; })(jQuery); $("div").lockDimensions("width").css("color", "red");

Поскольку плагин возвращает this в непосредственном теле его функции, он поддерживает цепочку вызовов и jQuery коллекцией можно продолжать манипулировать JQuery методами, такими, как к примеру .css . Так что если Ваш плагин не возвращает ценного значения, Вы должны всегда возвращать this в непосредственном теле функции плагина. Кроме того, параметры которые вы подаете при вызове плагина, подаются как аргументы функции плагина. В примере выше таким аргументом является type, а при вызове в него подается значение "width". Кстати, плагин Выше закрепляет высоту или ширину каждого блока на странице, в соответствии с его текущими размерами.

Умолчания и опции

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

(function($){ $.fn.tooltip = function(options) { var settings = { "location" : "top", "background-color" : "blue" }; return this.each(function() { // если опции существуют, то совмещаем их // со значениями по умолчанию if (options) { $.extend(settings, options); // при этом важен порядок совмещения } // код плагина тут }); }; })(jQuery); $("div.tools").tooltip({ "location" : "left" });

В этом примере, после вызова плагина tooltip с соответствующими опциями, в настройках по умолчанию затирается поле location на значение "left". В итоге Так настройки примут вид:

{ "location" : "left", "background-color" : "blue" }

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

$("div.tools").tooltip(); // все настройки останутся по умолчанию

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

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

Контент1 alert($("#myid1").html())// сперва метод вернет верное значение Контент1 jQuery.fn.html = function(){ return "Hello World"; } alert($("#myid1").html())// а затем "Hello World";

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

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

(function($){ $.fn.tooltip = function(options) { // ЭТО }; $.fn.tooltipShow = function() { // ОЧЕНЬ }; $.fn.tooltipHide = function() { // ПЛОХО }; $.fn.tooltipUpdate = function(content) { // !!! }; })(jQuery);

Такой код загромождает объект $.fn . Это рекомендуется, поскольку может помех до $. Fn имен. Чтобы исправить это, вы должны собрать все методы Вашего плагина в один объект, и вызывать метод по его строковому имени

(function($){ var methods = { init: function(options) { // ЭТО }, show: function() { // УЖЕ }, hide: function() { // ЛУЧШЕ))) }, update: function(content) { // !!! } }; $.fn.tooltip = function(method) { // логика вызова метода if (methods) { return methods[ method ].apply(this, Array.prototype.slice.call(arguments, 1)); } else if (typeof method === "object" || ! method) { return methods.init.apply(this, arguments); } else { $.error("Метод " + method + " в jQuery.tooltip не существует"); } }; })(jQuery); $("div").tooltip(); // вызов метода init $("div").tooltip({ // вызов метода init с параметрами foo: "bar" }); $("div").tooltip("hide"); // вызов метода hide $("div").tooltip("update", "Это новый контент!"); // вызов метода update с параметрами

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

События

Менее известных особенность метода bind является то, что он позволяет для одного пространства имен установить события. Если ваш плагин порождает некие события, хорошей практикой будет, чтобы событие привязывалось к Вашему пространству имен. Таким образом, если Вам нужно отключить позже, Вы можете сделать это без вмешательства в другие события, которые, возможно, были привязаны к одному типу событий. Вы можете использовать уникальные имена Ваших событий, путем добавления ".".

(function($){ var methods = { init: function(options) { return this.each(function(){ $(window).bind("resize.tooltip", methods.reposition); }); }, destroy: function() { return this.each(function(){ $(window).unbind(".tooltip"); }) }, reposition: function() { // ... }, show: function() { // ... }, hide: function() { // ... }, update: function(content) { // ...} }; $.fn.tooltip = function(method) { if (methods) { return methods.apply(this, Array.prototype.slice.call(arguments, 1)); } else if (typeof method === "object" || ! method) { return methods.init.apply(this, arguments); } else { $.error("Метод " + method + " не существует в jQuery.tooltip"); } }; })(jQuery); $("#fun").tooltip(); // некторое время спустя... $("#fun").tooltip("destroy");

В этом примере, когда плагин tooltip инициализируется методом init, он связывает метод reposition с событием resize окна в пространстве имен "tooltip". Позже, если разработчик должен уничтожить tooltip, мы можем отключить события, связанные c плагином, передав его имя, в данном случае "tooltip", в метод unbind. Это позволяет безопасно отключить события плагина, без случайной отмены привязки событий, которые были связаны с событиями за пределами плагина.

Данные

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

(function($){ var methods = { init: function(options) { return this.each(function(){ var $this = $(this), data = $this.data("tooltip"), tooltip = $("", { text: $this.attr("title") }); // плагин еще не инициализирован if (! data) { /* Дополнительные возможности установки */ $(this).data("tooltip", { target: $this, tooltip: tooltip }); } }); }, destroy: function() { return this.each(function(){ var $this = $(this), data = $this.data("tooltip"); $(window).unbind(".tooltip"); data.tooltip.remove(); $this.removeData("tooltip"); }) }, reposition: function() { // ... }, show: function() { // ... }, hide: function() { // ... }, update: function(content) { // ...} }; $.fn.tooltip = function(method) { if (methods) { return methods.apply(this, Array.prototype.slice.call(arguments, 1)); } else if (typeof method === "object" || ! method) { return methods.init.apply(this, arguments); } else { $.error("Method " + method + " does not exist on jQuery.tooltip"); } }; })(jQuery);

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

Резюме

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

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