6

Для упражнений я создаю плагин jQuery, простой слайдер изображений. Я использую шаблон от Boilerplate - jQuery Plugins.jQuery Plugin Development Как сохранить переменные и методы private

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

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

Я много искал Google и нашел (не только) это решение на складе overflow: global or local variables in a jquery-plugin. В принятом ответе предлагается хранить значения, которые должны быть частными в HTML-разметке, атрибуте data-whatever.

Это работает очень хорошо, но не очень приятно.

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

(function($) { 

$.pluginName = function(element, options) { 
.... 
var plugin = this; 
.... 
     // a public method 
    plugin.foo_public_method = function() { 
      .... 
    } 

    // private methods 
    var foo_private_method = function() { 
      .... 
    } 
    plugin.init(); 

} .... 

Посмотрел довольно просто - но я не в состоянии осуществить это решение!

Так что мой вопрос: как реализовать приватную переменную в следующем шаблоне плагина? (И как мне это правильно называть изнутри Plugin.prototype ...)

Я создал Fiddle с моим плагином. Резюме кода:

(function ($, window, document, undefined) { 

var pluginName = "easyCarousel"; 

// default configuration object 
defaults = { 
     ... default values here, css etc 
    } 
}; 

// The actual plugin constructor 
function Plugin(element, options) { 

    this.element = element; 
    this.options = $.extend({}, defaults, options); 
    this._defaults = defaults; 
    this._name = pluginName; 
    this.init(); 
} 

Plugin.prototype = { 

    init: function() { 

     var options = this.options; 
     this.options.stage = $(this.element); 
     .... calling/starting views and controllers 

    }, 

    buildCollectionView: function (options, Helper) { 
     .... setting markup, applying css, calulating dimensions 
    }, 

    buildStageView: function (options, Helper) { 

     .... setting markup, applying css 
     .... storing calculated slide width in data Attribute 

     stage.attr({ 
      'data-slidewidth': width, 
      'data-stagewidth': setWidth 
     }); 
    }, 

    buildTheatreView: function (options, Helper) { 

     .... setting markup, applying css 

    }, 

    buildNavigationView: function (options) { 

     .... setting markup 

    }, 


    navigationController: 

    function (options, slideForward, slideBackward) { 

     .... event binding 

     pubSub.on("navigation:arrownext:click", function (e) { 
      slideForward(options, e); 
     }); 

     $('.carousel__arrownext', options.theatre) 
     .bind('click', function() { 
      pubSub.trigger("navigation:arrownext:click", this); 
     }); 
    }, 

    slideForwardAnimation: function (options, e) { 

     .... reading stored width value from data Attribute 

     $element.animate({ 
      "left": "-=" + slideWidth 
     }) 
    }, 


    setDimensionsHelper: function (options) { 

     .... calculating an returning dimensions of the slider 
    }, 

    eventBusHelper: function (options) { 
     // integrating third party eventbus 
    } 
}; 

$.fn[pluginName] = function (options) { 

    return this.each(function() { 
     if (!$.data(this, "plugin_" + pluginName)) { 
      $.data(this, "plugin_" + pluginName, 
      new Plugin(this, options)); 
     } 
    });  
}})(jQuery, window, document); 

Надеюсь, что мой пример кода не сложный/долго просматриваемый.

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

Заранее спасибо :)

+0

«* Каждое значение, которое я пытался сохранить, перезаписаны последней инстанции - в порядке, вот что прототип наследование делает * "- um, нет. – Bergi

+0

Я не понимаю, зачем вам нужны «частные» переменные для вашего плагина? Кроме того, если они локальны для конструктора экземпляра, это означает, что вы не можете получить их от прототипа. – Bergi

+0

«.. почему бы вам« частное »?«Просто для последующего использования. Я вычисляю ширину слайда при построении карусели. Позже мне нужна эта ширина, когда нажимается следующая кнопка (скользящая карусель, эта ширина x дальше). Легче прочитать это значение от переменной, чем пересчитывая его снова и снова (надеюсь, что термин private правильный в этом контексте). Я начинаю задумываться, не понял ли я всю концепцию, и мои вычисления не должны идти в прототип. Как бы вы попытались достичь этого? ответ! – smaug333

ответ

3

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

Кроме того, у вас нет ключевого слова «var» перед вашим определением «по умолчанию», поэтому вы на самом деле создаете глобальную переменную, называемую «по умолчанию», а не та, которая ограничена только вашим закрытием.

Это то, что я бы рекомендовал:

// default configuration object 
var defaults = { 
     ... default values here, css etc 
    } 
}; 

// The actual plugin constructor 
function Plugin(element, options) { 
    this._defaults = defaults; 
    this._name = pluginName; 
    this.init(element, options); 
} 

Plugin.prototype = { 

    init: function (element, options) { 
     this.element = element; 
     this.options = $.extend({}, this._defaults, options); 
     this.options.stage = $(this.element); 
     .... calling/starting views and controllers 

    }, 

или даже лучше:

// The actual plugin constructor 
function Plugin(element, options) { 
    this.init(element, options); 
} 

Plugin.prototype = { 

    _name: 'put your name here', 

    _defaults: { 
     // just define them here, no need for an outside variable 
    }, 

    init: function (element, options) { 
     this.element = element; 
     this.options = $.extend({}, this._defaults, options); 

     // why are you saving stage as an option? That doesn't make sense. 
     this.options.stage = $(this.element); 
     // Makes more sense to just do this ($el is a more standard name for this) 
     this.$el = $(this.element); 
     // .... calling/starting views and controllers 

    }, 
+0

Спасибо, очень элегантный и работает как шарм – smaug333

+0

I в объявлении параметров отсутствует «var». Sigh ... – Bobort