Создаем плагин для jQuery

Владимир | | CSS, HTML, JavaScript, Web разработка.

jquery plugin logo

Этот пост – вольный перевод очень полезной статьи Jeffrey Way Learn How to Create a jQuery Plugin.

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

Вы можете скачать исходники этого примера или посмотреть демонстрацию.

У вас может возникнуть мысль: «Что за суета вокруг jQuery? Нужно загрузить кучу плагинов чтобы эта библиотека на что-нибудь годилась». Первое, это не так. Второе, jQuery специально разрабатывалась для широкого применения. Сохраняя ядро библиотеки маленьким – 16кБ (прим. – речь идет о сжатом варианте) – пользователи могут добавить дополнительные плагины по собственному усмотрению. Сегодня, я покажу вам, как создать собственный плагин под названием «Center» с нуля. Приступим!

Наша задача

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

Нам потребуется совсем не много. Просто убедитесь, что вы скачали библиотеку jQuery.

Шаг 1

Первый шаг при разработке плагина – это создание нового JavaScript файла. В соответствии с соглашением об именах этот файл нужно назвать «YourPluginName.jQuery.js». Как только вы создали этот файл, убедитесь, что подключили его к странице.

<head>
    <script src="jquery-1.2.6.pack.js" type="text/javascript">
    <script src="center.jQuery.js" type="text/javascript">
</head>

Шаг 2

Теперь, скопируйте следующий код.

(function($){
$.fn.center = function(){
var element = this;
$(element).load(function(){
changeCss();
$(window).bind("resize", function(){
    changeCss();
});

function changeCss(){
    var imageHeight = $(element).height();
    var imageWidth = $(element).width();
    var windowWidth = $(window).width();
    var windowHeight = $(window).height();

    $(element).css({
        "position" : "absolute",
        "left" : windowWidth / 2 - imageWidth / 2,
        "top" : windowHeight /2 - imageHeight / 2
    });
};
});

}; })(jQuery);

Я подробно объяснял все в видеоролике (прим. – на англ.), но хочу остановиться на нескольких ключевых моментах. Каждый ваш плагин должен находиться внутри:

$.fn.center = function(){};

«сenter» необходимо заменить на название вашего плагина. Это укажет jQuery, что вы добавляете новый метод. На данный момент он не делает ничего, но мы может его вызвать так:

$(function(){
    $("#someElement").center();
});

Шаг 3

Вы должны понимать, как вручную центрировать картинку на странице до того как начнете создавать плагин. Первое, ваш элемент должен быть абсолютно позиционирован. В противном случае, он не будет двигаться после изменения значений «left» и «top«. Далее, картинка должна быть сдвинута на 50% ширины браузера влево. И, наконец, чтобы компенсировать ширину картинки, мы должны вычесть половину ее ширины (т.е. мы рассчитываем координаты ее левой стороны – прим.).

function changeCss(){
    var imageHeight = $(element).height();
    var imageWidth = $(element).width();
    var windowWidth = $(window).width();
    var windowHeight = $(window).height();

    $(element).css({
        "position" : "absolute",
        "left" : windowWidth / 2 - imageWidth / 2,
        "top" : windowHeight /2 - imageHeight / 2
    });
};

Таким образом, мы точно размещаем центр картинки в центре страницы.

Шаг 4

Продолжаем, нам нужно создать обработчик изменения размеров окна браузера.

$(window).bind("resize", function(){
    changeCss();
});

Функция ChangeCss() присваивает новые координаты левому верхнему углу нашей картинки. Каждый раз при изменении размеров окна она будет пересчитывать эти значения.

Готово!

Если у вас возникли вопросы, можете спокойно задавать их в комментариях. И, как всегда, плагин не готов для использования в «живых» приложениях. Что произойдет если у пользователя выключен JavaScript? И конечно, есть несколько способов сделать то же самое на «чистом» CSS.

  • http://mefolio.ru/ Евгений

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

    Еще один момент, я не объявлял бы следующие переменные:

    var imageHeight = $(element).height();
    var imageWidth = $(element).width();
    var windowWidth = $(window).width();
    var windowHeight = $(window).height();

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

    • http://www.simplecoding.org/ Владимир

      >> я не объявлял бы следующие переменные

      Согласен, в реальном приложении это не нужно, но для учебного примера чем подробнее, тем лучше ;)

      >> все зависит от родительского элемента

      Да, это неточность в описании. Но, в принципе, задумано правильно. Если нужно отцентрировать блок внутри какого-то контейнера, то просто размещаете блок в нем.

  • http://mefolio.ru/ Евгений

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

    Еще один момент, я не объявлял бы следующие переменные:

    var imageHeight = $(element).height();
    var imageWidth = $(element).width();
    var windowWidth = $(window).width();
    var windowHeight = $(window).height();

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

    • http://www.simplecoding.org/ Владимир

      >> я не объявлял бы следующие переменные

      Согласен, в реальном приложении это не нужно, но для учебного примера чем подробнее, тем лучше ;)

      >> все зависит от родительского элемента

      Да, это неточность в описании. Но, в принципе, задумано правильно. Если нужно отцентрировать блок внутри какого-то контейнера, то просто размещаете блок в нем.

  • http://satelit2.at.ua/ ivanko

    а подробнее можно про те переменные, которые Вы бы не объявляли?

    • http://mefolio.ru/ Евгений

      function changeCss()
      {
      $(element).css({
      «position» : «absolute»,
      «left» : $(window).width() / 2 — $(element).width() / 2,
      «top» : $(window).height() /2 — $(element).height() / 2
      });
      };

  • http://satelit2.at.ua/ ivanko

    а подробнее можно про те переменные, которые Вы бы не объявляли?

    • http://mefolio.ru/ Евгений

      function changeCss()
      {
      $(element).css({
      «position» : «absolute»,
      «left» : $(window).width() / 2 — $(element).width() / 2,
      «top» : $(window).height() /2 — $(element).height() / 2
      });
      };

  • Жека
    • http://www.simplecoding.org/ Владимир

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

      • неясыть

        Типа того … )

        $(document).ready(function(){
        if((detect.indexOf('safari')) != -1) {
        document.getElementById('bheaderA').innerHTML = 'Задать вопрос';
        document.getElementById('bheaderTwo').style.display = 'none';
        } else {
        $("#faqget").click(function () {
        renameLine();
        $("#faq").slideToggle("slow");
        $("#faqform").slideToggle("slow");
        });
        }
        });

        • http://www.simplecoding.org/ Владимир

          Ещё нужно добавить

          var detect = navigator.userAgent.toLowerCase();

          и

          function renameLine()
          {
          var one = document.getElementById('bheaderA');
          var two = document.getElementById('bheaderATwo');
          if (one.innerHTML == 'Задать вопрос') {
          one.innerHTML = 'Вопросы и ответы';
          two.innerHTML = 'Задать вопрос';
          } else {
          two.innerHTML = 'Вопросы и ответы';
          one.innerHTML = 'Задать вопрос';
          }
          }

          ;)

  • Жека
    • http://www.simplecoding.org/ Владимир

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

      • неясыть

        Типа того … )

        $(document).ready(function(){
        if((detect.indexOf('safari')) != -1) {
        document.getElementById('bheaderA').innerHTML = 'Задать вопрос';
        document.getElementById('bheaderTwo').style.display = 'none';
        } else {
        $("#faqget").click(function () {
        renameLine();
        $("#faq").slideToggle("slow");
        $("#faqform").slideToggle("slow");
        });
        }
        });

        • http://www.simplecoding.org/ Владимир

          Ещё нужно добавить

          var detect = navigator.userAgent.toLowerCase();

          и

          function renameLine()
          {
          var one = document.getElementById('bheaderA');
          var two = document.getElementById('bheaderATwo');
          if (one.innerHTML == 'Задать вопрос') {
          one.innerHTML = 'Вопросы и ответы';
          two.innerHTML = 'Задать вопрос';
          } else {
          two.innerHTML = 'Вопросы и ответы';
          one.innerHTML = 'Задать вопрос';
          }
          }

          ;)

  • http://webering.ru/site Веб-студия Webering

    Ребята, вы еще забыли подключить JQuery.

    • http://www.simplecoding.org/ Владимир

      Где именно забыли?
      Первый листинг, строка 2
      <script src=»jquery-1.2.6.pack.js» type=»text/javascript»>

  • http://webering.ru/site Веб-студия Webering

    Ребята, вы еще забыли подключить JQuery.

    • http://www.simplecoding.org/ Владимир

      Где именно забыли?
      Первый листинг, строка 2
      <script src=»jquery-1.2.6.pack.js» type=»text/javascript»>

  • Maikl

    а можно вопрос нафига сначала вызывать функцию changeCss(); и потом еще при bind'e

    #
    (function($){
    #
    $.fn.center = function(){
    #
    var element = this;
    #
    $(element).load(function(){
    #
    changeCss();
    #
    $(window).bind("resize", function(){
    #
    changeCss();

    #
    });

    • http://www.simplecoding.org/ Владимир

      Первый раз (строка 5) функция changeCss() вызывается сразу после загрузки страницы (и центрирует блок).
      Но нам нужно, чтобы эта функция вызывалась каждый раз при изменении размеров окна. Поэтому мы создаем обработчик события «resize» (строки 6-8) и вызываем функцию changeCss() в нем.
      Т.е. функция changeCss() будет вызвана 1 раз сразу после загрузки страницы и 1 раз после каждого изменения размеров окна браузера.

      • http://mefolio.ru/ Евгений

        Тогда лучше так:


        $(this).load( function() {
        $(window).bind("resize", function(){
        changeCss();
        }).trigger("resize");
        });

        дабы не дублировать.

        • http://www.simplecoding.org/ Владимир

          Я согласен, что дублировать код — плохо.
          Но, во-первых, в данном случае речь идет о двух вызовах одной и той же функции. А они [функции] как раз и предназначены для того, чтобы можно было вызывать один и тотже код несколько раз.
          Если вызов только один, то в принципе нет смысла создавать функцию (можно сразу разместить нужный код внутри метода bind).
          Во-вторых, генерировать событие «resize» сразу после загрузки страницы только ради того, чтобы вызвать функцию, как-то не очень красиво ;)

      • http://mefolio.ru/ Евгений

        Владимир, моя ошибка, в прошлых версиях jQuery trigger — не приводил к появлению события, а вызывал обработчики, как обычные функции. «Обновил» знания, предоженную вами задачу можно решить следующим способом:

        (function($){
        $.fn.center = function(){
        return $(this).load(function(){
        var self = this;
        $(window).bind("resize", function(){
        $(self).css({
        "position" : "absolute",
        "left" : $(window).width() / 2 - $(self).width() / 2,
        "top" : $(window).height() /2 - $(self).height() / 2
        });
        }).triggerHandler('resize');
        });
        };
        })(jQuery);

        PS. из функции $.fn.center вы забыли вернуть обернутый элемент, что привело бы к обрыванию «цепочки».

        • http://mefolio.ru/ Евгений

          хм, думаю, что правильнее все-таки так:

          (function($){
          $.fn.center = function(){
          return this.each(function(){
          $(this).load(function(){
          var self = this;
          $(window).bind("resize", function(){
          $(self).css({
          "position" : "absolute",
          "left" : $(window).width() / 2 - $(self).width() / 2,
          "top" : $(window).height() /2 - $(self).height() / 2
          });
          }).triggerHandler('resize');
          });
          });
          };
          })(jQuery);

        • http://www.simplecoding.org/ Владимир

          Честно говоря, я ничего не забывал :) — это перевод статьи с nettuts.com.
          Большое спасибо за это замечание! Действительно из-за таких «мелочей» потом возникают очень неприятные баги.

          Последний вариант кода действительно красиво выглядит и хорошо демонстрирует возможности jQuery.

  • Maikl

    а можно вопрос нафига сначала вызывать функцию changeCss(); и потом еще при bind'e

    #
    (function($){
    #
    $.fn.center = function(){
    #
    var element = this;
    #
    $(element).load(function(){
    #
    changeCss();
    #
    $(window).bind("resize", function(){
    #
    changeCss();

    #
    });

    • http://www.simplecoding.org/ Владимир

      Первый раз (строка 5) функция changeCss() вызывается сразу после загрузки страницы (и центрирует блок).
      Но нам нужно, чтобы эта функция вызывалась каждый раз при изменении размеров окна. Поэтому мы создаем обработчик события «resize» (строки 6-8) и вызываем функцию changeCss() в нем.
      Т.е. функция changeCss() будет вызвана 1 раз сразу после загрузки страницы и 1 раз после каждого изменения размеров окна браузера.

      • http://mefolio.ru/ Евгений

        Тогда лучше так:


        $(this).load( function() {
        $(window).bind("resize", function(){
        changeCss();
        }).trigger("resize");
        });

        дабы не дублировать.

        • http://www.simplecoding.org/ Владимир

          Я согласен, что дублировать код — плохо.
          Но, во-первых, в данном случае речь идет о двух вызовах одной и той же функции. А они [функции] как раз и предназначены для того, чтобы можно было вызывать один и тотже код несколько раз.
          Если вызов только один, то в принципе нет смысла создавать функцию (можно сразу разместить нужный код внутри метода bind).
          Во-вторых, генерировать событие «resize» сразу после загрузки страницы только ради того, чтобы вызвать функцию, как-то не очень красиво ;)

      • http://mefolio.ru/ Евгений

        Владимир, моя ошибка, в прошлых версиях jQuery trigger — не приводил к появлению события, а вызывал обработчики, как обычные функции. «Обновил» знания, предоженную вами задачу можно решить следующим способом:

        (function($){
        $.fn.center = function(){
        return $(this).load(function(){
        var self = this;
        $(window).bind("resize", function(){
        $(self).css({
        "position" : "absolute",
        "left" : $(window).width() / 2 - $(self).width() / 2,
        "top" : $(window).height() /2 - $(self).height() / 2
        });
        }).triggerHandler('resize');
        });
        };
        })(jQuery);

        PS. из функции $.fn.center вы забыли вернуть обернутый элемент, что привело бы к обрыванию «цепочки».

        • http://mefolio.ru/ Евгений

          хм, думаю, что правильнее все-таки так:

          (function($){
          $.fn.center = function(){
          return this.each(function(){
          $(this).load(function(){
          var self = this;
          $(window).bind("resize", function(){
          $(self).css({
          "position" : "absolute",
          "left" : $(window).width() / 2 - $(self).width() / 2,
          "top" : $(window).height() /2 - $(self).height() / 2
          });
          }).triggerHandler('resize');
          });
          });
          };
          })(jQuery);

        • http://www.simplecoding.org/ Владимир

          Честно говоря, я ничего не забывал :) — это перевод статьи с nettuts.com.
          Большое спасибо за это замечание! Действительно из-за таких «мелочей» потом возникают очень неприятные баги.

          Последний вариант кода действительно красиво выглядит и хорошо демонстрирует возможности jQuery.