jQuery插件设计模式(通常的做法),用于处理私有功能 [英] jQuery plugin design pattern (common practice?) for dealing with private functions

查看:160
本文介绍了jQuery插件设计模式(通常的做法),用于处理私有功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我的插件一般看起来像这样:

 (function($){

$ .fn.myplugin = function(...){
...
//某些共享功能,例如:
this.css('background-color','green');
...
};
$ .fn.mypluginAnotherPublicMethod = function(...){
...
//某些共享功能,例如:
this.css('background-color' 'red');
...
};

}(jQuery));

现在我的问题是:如何整洁地共享这个共享功能?一个明显的解决方案是将其放在插件的命名空间中的一个函数中:

  var fill = function($ obj,color) {
$ obj.css('background-color',color);
};

虽然这个解决方案是有效的,很好的命名空间,我真的不喜欢它。一个简单的原因:我必须传递它的jQuery对象。即我必须这样调用: fill(this,'red'); ,而我想像这样调用: this.fill ('red');



当然,我们可以通过简单地将 fill into jQuery.fn 。但这感觉很不舒服想象一下,根据这种方法开发了十个插件,每个插件将五个私有功能放入jQuery函数命名空间中。最后一大堆乱七八糟我们可以通过将这些功能中的每个功能与他们所属的插件的名称进行前缀来减轻,但这并不意味着它更具吸引力。这些功能应该是插件的私有的,所以我们不想将它们暴露给外部世界(至少不是直接的)。



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






更新:感谢您的建议。



我特别喜欢David的定义一个包含私有函数并包装jQuery对象的对象类型的想法。唯一的问题是它仍然不允许我链接私人和公共功能。想要像 this.fill('red')之类的语法开始是很大的理由。



我最终得到一个我认为不是很优雅的解决方案,但吸引了两个世界最好的事业:

  $。 fn.chain = function(func){
return func.apply(this,Array.prototype.slice.call(arguments,1));
};

其中允许的结构如下:

 此。 
find('。acertainclass')。
chain(fill,'red')。
click(function(){
alert(I'm red);
});

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




解决方案

有一件事:如果你想打电话给 this.fill('red'); 其中这个是jQuery的一个实例,您必须扩展jQuery原型,并使 fill()public。 jQuery提供了使用所谓的插件扩展它的原型的准则,可以使用 $。fn.fill 添加,这与 jQuery相同。原型.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('背景',col);
返回此;
},
颜色:function(col){
this.elem.css('color',col);
返回这个;
}
}

$ .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')//应该打印'true'

这样,P代表你自己的私有功能的工具箱。除非你将它们附加到某个地方,否则它们将不会在代码或jQuery命名空间中的任何地方都可用。您可以在Private对象中添加任意多种方法,只要返回 ,您也可以像我在示例中一样链接jQuery样式。


I've been developing jQuery plugins for quite some time now, and I like to think I know how to design one well by now. One issue keeps nagging me though, and that is how to deal with private functions in a powerful yet elegant manner.

My plugins generally look something like this:

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

Now my question is: how to neatly DRY up that shared functionality? An obvious solution would be to put it in a function within the plugin's namespace:

var fill = function($obj, color) {
  $obj.css('background-color', color);
};

Although this solution is effective and nicely namespaced, I really dislike it. For one simple reason: I have to pass it the jQuery object. I.e. I have to call it like this: fill(this, 'red');, while I would like to call it like this: this.fill('red');

Of course we could achieve this result by simply putting fill into jQuery.fn. But that feels very uncomfortable. Imagine having ten plugins developed based on this approach and each plugin putting five of those 'private' functions into the jQuery function namespace. It ends up in a big mess. We could mitigate by prefixing each of these functions with the name of the plugin they belong to, but that doesn't really make it more attractive. These functions are supposed to be private to the plugin, so we do not want to expose them to the outside world at all (at least not directly).

So there's my question: does anyone of you have suggestions for how to get the best of both worlds. That is; plugin code being able to call 'private' plugin functions in a way similar to this.fill('red') (or this.myplugin.fill('red') or even this.myplugin().fill('red') etc.), while preventing jQuery function namespace pollution. And of course it should be light-weight, as these private functions might be called very frequently.


UPDATE: Thanks for your suggestions.

I especially like David's idea of defining an object type that holds the 'private' functions and wraps a jQuery object. The only problem with it is that it still disallows me from chaining 'private' and 'public' functions. Which was big reason to want a syntax like this.fill('red') to begin with.

I ended up with a solution which I consider not tremendously elegant, but appealing to the 'best of both worlds' cause:

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

Which allows for constructs like:

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

I cross-posted my question in other places, which also collected some interesting responses:

解决方案

One thing first: if you would like to call something like this.fill('red'); where this is an instance of jQuery, you have to extend the jQuery prototype and make fill() "public". jQuery provides guidelines for extending it's prototype using so called "plugins" that can be added using $.fn.fill, which is the same as jQuery.prototype.fill.

In jQuery callbacks, this is often a reference to the HTML Element, and you can't add prototypes to those (yet). That is one of the reason why jQuery wraps elements and return jQuery instances that can be easily extended.

Using the (function(){})(); syntax, you can create and execute "private" javascript on the fly, and it all disappears when it's done. Using this technique, you can create your own jQuery-like syntax that wraps jQuery into your own private chainable object.

(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'

This way, the P stands for your own toolbox of "private" functions. They won't be available anywhere else in the code or in the jQuery namespace unless you attach them somewhere. You can add as many methods as you like in the Private object, and as long as you return this, you can also chain them jQuery-style as I did in the example.

这篇关于jQuery插件设计模式(通常的做法),用于处理私有功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆