jQuery 插件开发如何保持变量和方法私有

jQuery Plugin Development how to keep variables and methods private

出于练习目的,我正在创建一个 jQuery 插件,一个简单的图像滑块。我使用 Boilerplate - jQuery Plugins.

中的模式

在初始化过程中,一切都按预期进行,每个实例都获得了设置所需的正确值(宽度和高度,以及事件绑定)。

当我尝试将计算出的幻灯片宽度传递给执行动画的函数(单击下一步按钮)时,问题就来了。我试图保存的每个值都被最后一个实例覆盖 - 好的,这就是原型继承所做的,正如我所了解的。

我在 google 上搜索了很多并在 stockoverflow 上找到了(不仅)这个解决方案: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);

希望我的代码示例不要complicated/long查看

如您所见,我对高级 Javascript 模式还很陌生 - 现在我真的卡住了。我已经在这个问题上花了很多时间。因此,我们非常感谢您的每一次帮助尝试。当然还有对代码的每次审查。

提前致谢:)

您需要做的就是在原型中定义变量(直接或从原型中的方法中),而不是在构造函数中进行。构造函数中定义的变量将在插件的所有实例之间共享,而原型中定义的变量将按实例共享。

此外,您的 "defaults" 定义前面没有 "var" 关键字,因此您实际上是在创建一个名为 "defaults" 的全局变量,而不是一个仅限于您的变量关闭。

这是我推荐的:

// 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

    },