jQuery 插件开发如何保持变量和方法的私密性

jQuery Plugin Development how to keep variables and methods private

本文关键字:方法 私密性 变量 何保持 插件 开发 jQuery      更新时间:2023-09-26

出于练习目的,我正在创建一个jQuery插件,一个简单的图像滑块。我使用来自样板的模式 - jQuery 插件。

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

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

我用谷歌搜索了很多,发现(不仅)这个解决方案在 stockoverflow 上:jquery-plugin 中的全局或局部变量。接受的答案建议将需要私有的值存储在HTML标记中,即data-what属性。

这很好用,但不是很好。

第二个答案似乎更优雅,将真正的私有变量保留在每个实例的范围内:

(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();
} ....

看起来很简单 - 但我无法实现这个解决方案!

所以我的问题是:如何在以下插件模式中实现私有变量?(以及如何从插件原型内部正确调用它......

我用我的插件创建了一个小提琴。代码摘要:

(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模式很陌生 - 现在我真的卡住了。我已经在这个问题上花了很多时间。因此,非常感谢我们每一次提供帮助的尝试。当然,每次对代码的审查也是如此。

提前致谢:)

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

此外,在"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
    },