用于处理私有函数的jQuery插件设计模式(通用实践?)

Tim*_*ijk 9 javascript jquery plugins design-patterns

我一直在开发jQuery插件已有一段时间了,我想我现在知道如何设计好一个.然而,有一个问题一直困扰着我,那就是如何以强大而优雅的方式处理私有功能.

我的插件通常看起来像这样:

(function($) {

  $.fn.myplugin = function(...) {
    ...
    // some shared functionality, for example:
    this.css('background-color', 'green');
    ...
  };
  $.fn.mypluginAnotherPublicMethod = function(...) {
    ...
    // some shared functionality, for example:
    this.css('background-color', 'red');
    ...
  };

}(jQuery));
Run Code Online (Sandbox Code Playgroud)

现在我的问题是:如何巧妙地干掉共享功能?一个明显的解决方案是将它放在插件命名空间中的函数中:

var fill = function($obj, color) {
  $obj.css('background-color', color);
};
Run Code Online (Sandbox Code Playgroud)

虽然这个解决方案很有效且命名很好,但我真的不喜欢它.原因很简单:我必须传递jQuery对象.即我必须这样称呼它:fill(this, 'red');,虽然我想这样称呼它:this.fill('red');

当然,我们可以达到这个结果简单地把filljQuery.fn.但这感觉非常不舒服.想象一下,在此基础上的方法和每个插件把这些"私人"功能,五成jQuery函数命名空间开发10个插件.它最终陷入了混乱.我们可以通过在前面的每一个与他们属于插件的名称,这些功能减少,但并没有真正使其更具吸引力.这些功能应该是私有的插件,所以我们不希望他们在所有的(直接至少不会)暴露于外界.

所以我的问题是:你们中是否有人有关于如何充分利用两个世界的建议.那是; 插件代码能够调用的方式类似"私人"的插件功能this.fill('red')(或者this.myplugin.fill('red')甚至this.myplugin().fill('red')等),同时防止jQuery函数命名空间的污染.当然它应该是轻量级的,因为这些私有函数可能会被频繁调用.


更新:感谢您的建议.

我特别喜欢David的定义一个包含'private'函数并包装jQuery对象的对象类型的想法.唯一的问题是它仍然不允许我链接"私人"和"公共"功能.这是想要this.fill('red')开始使用语法的重要原因.

我最终找到了一个我认为不是非常优雅的解决方案,但却吸引了"两全其美"的原因:

$.fn.chain = function(func) {
    return func.apply(this, Array.prototype.slice.call(arguments, 1));
};
Run Code Online (Sandbox Code Playgroud)

这允许构造如:

this.
    find('.acertainclass').
    chain(fill, 'red').
    click(function() {
        alert("I'm red");
    });
Run Code Online (Sandbox Code Playgroud)

我在其他地方交叉发布了我的问题,这也收集了一些有趣的回答:

Dav*_*ing 11

有一两件事第一:如果你想打电话给像this.fill('red');这里这个是jQuery的实例,你必须扩展jQuery的原型,让fill()"公开".jQuery提供了使用所谓的"插件"来扩展它的原型的指南,这些插件可以使用$.fn.fill,它是相同的jQuery.prototype.fill.

在jQuery回调中,通常是对HTML元素的引用,并且您无法向那些(还)添加原型.这就是为什么jQuery包装元素并返回可以轻松扩展的jQuery实例的原因之一.

使用(function(){})();语法,您可以动态创建和执行"私有"javascript,并在完成后消失.使用这种技术,您可以创建自己的类jQuery语法,将jQuery包装到您自己的私有可链接对象中.

(function(){
    var P = function(elem) {
        return new Private(elem);
    };
    var Private = function(elem) {
        this.elem = jQuery(elem);
    }
    Private.prototype = {
        elem: null,
        fill: function(col) {
            this.elem.css('background',col);
            return this;
        },
        color: function(col) {
            this.elem.css('color', col);
            return this;
        }
    }

    $.fn.myplugin = function() {
        P(this).fill('red');
    };
    $.fn.myotherplugin = function() {
        P(this).fill('yellow').color('green');
    };

})();

$('.foo').myplugin();
$('.bar').myotherplugin();

console.log(typeof P === 'undefined') // should print 'true'
Run Code Online (Sandbox Code Playgroud)

这样,P代表您自己的"私有"功能工具箱.它们将无法在代码中的任何其他位置或jQuery命名空间中使用,除非您将它们附加到某处.你可以在Private对象中添加任意数量的方法,只要你返回,你也可以像我在示例中那样链接它们jQuery样式.


K P*_*ime 2

怎么样(在插件的范围内):

var fill = function ()
{
    (function (color) 
    {
        this.css ('backgrorund-color', color);
        //.. your stuff here ...
    }).apply (this, arguments);
}

$.fn.myplugin = function ()
{
    fill ('green');
}
Run Code Online (Sandbox Code Playgroud)

这样, fill 将保留您所在的 jQuery 上下文,并且仍然是您的插件私有的


修正:上面的范围界定不正确,请尝试以下操作:

var fill = function (color)
{
    if (!$this) return; // break if not within correct context

    $this.css ('backgrorund-color', color);
    //.. your stuff here ...
}

$.fn.myplugin = function ()
{
    var $this = $(this); // local ref to current context
    fill ('green');
}
Run Code Online (Sandbox Code Playgroud)