用函数包装 jQuery 插件

Wrap jQuery plugin with a function

假设我有以下简单插件:

(function ( $ ) {
    $.fn.greenify = function() {
       this.css( "color", "green" );
       return this;
    };
}( jQuery ));

我不想对插件本身做任何更改,但我想用另一个函数包装并扩展其​​命名空间,如下所示:

(function($) {
    $.fn.myFunction = function () {
        (function ($) {
            $.fn.greenify = function () {
                this.css("color", "green");
                return this;
            };
        }(jQuery));
    };
})(jQuery);

所以我可以这样调用插件函数:

$(selector). myFunction().greenify();

基本上我想禁止直接调用‘greenify’函数。

可能吗?

如果您想创建自己的上下文,一种方法是 return 具有一组功能的对象:

(function($) {
    $.fn.myFunction = function () {
        // Cache jQuery object
        var $this = this;

        // Return interface that acts on jQuery object
        return {
            greenify: function () {
                $this.css("color", "green");
                return $this;
            }
        };
    };
})(jQuery);

然后你可以调用它:

$(selector).myFunction().greenify();

Fiddle

编辑:但作为警告,当您这样做时,您将在调用 .myFunction 后离开 jQuery 链接上下文,这可能 非常 令人困惑在代码中。

我认为您在谈论方法链接,这是 jQuery 方法的优点。如下定义新方法,但保持 greenify() 不变:

(function($) {
    $.fn.myFunction = function () {
        return this.each(function() {
            //Do stuff
        });
    };
})(jQuery);

(function ( $ ) {
    $.fn.greenify = function() {
       this.css( "color", "green" );
       return this;
    };
}( jQuery ));
(function($) {
    $.fn.myFunction = function () {
        return this.each(function() {
            $(this).css({border:'1px solid black',textAlign:'center'});
        });
    };
})(jQuery);

$('.box').myFunction().greenify();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">COLOR CHANGE</div>

很确定,只要你的 myFunction returns this,你就应该能够链接任何你想要的东西。

(function ( $ ) {
    $.fn.greenify = function() {
       this.css( "color", "green" );
       return this;
    };
}( jQuery ));

(function($) {
    $.fn.myFunction = function () {
        // Do some stuff
        return this;
    };
})(jQuery);

$(selector).myFunction().greenify();

编辑:如果重点是"disable calling greenify directly",你为什么要首先扩展jQuery? 'greenify 可以通过传递某种参数来嵌套和触发。类似于:

(function($) {
    $.fn.myFunction = function (options) {
        // Do some stuff

        if (options.greenify) {
            this.css("color", "green");
        }

        return this;
    };
})(jQuery);

$(selector).myFunction({greenify: true});

... 或者您可以将 greenify 定义为函数(而不是插件)并调用它。但是定义插件的目的是让它们可以全局调用。

你肯定不想采用当前显示的方法,因为每次调用 myFunction 时,它也会分配 greenify。只需使用您的 myFunction 插件,为构建的 jQuery 对象分配一个标志,然后在 greenify 中检查该标志。

(function($) {
    $.fn.myFunction = function () {
        this.greenMarker = true;
        return this;
    };
    $.fn.greenify = function () {
        if(!this.greenMarker) return this;
        this.css("color", "green");
        return this;
    };
})(jQuery);

$('.f').greenify();
$('.g').myFunction().greenify();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="f">No Green</div>
<div class="g">Green Me</div>

问题并不清楚,但我假设简单插件 "greenify" 是第三方或其他 "forced to use" 插件,无论出于何种原因,您都无法更改。我们还假设它实际上是一个相当复杂的插件,为了问题的缘故进行了简化。

这意味着

  • 你不能改变它
  • 您不能在包装器中复制整个插件

通常覆盖的方法是复制一份,然后让新版本做你想做的,可能会调用旧版本,例如:

var oldfoo = foo;
foo = function() { 
    alert("foo called");
    oldfoo();  // or oldfoo.apply(this) to be clearer
}

这里可以应用相同的原则,但是将 'foo'(在上面的示例中)设置为 null - 以摆脱它,例如:

var oldfoo = foo;
newfoo = function() { 
    alert("foo called");
    oldfoo();  // or oldfoo.apply(this) to be clearer
}
foo = null;

复杂的是 jquery 并希望保持方法链接,这可以通过存储 'this' 并根据需要应用它来实现。

这是完整的代码和解释注释:

// The original plugin to be wrapped
(function ( $ ) {
    $.fn.greenify = function() {
       // changed to background-color for more impact (demo purposes)
       this.css( "background-color", "lightgreen" );
       return this;
    };
}( jQuery ));

(function($) {

    // allow this to be referred to later 
    // inside another loop where 'this' is something else
    var me = this;  

    // take a copy of the original
    // this stays inside the scope of (function($)) so can't be seen outside
    me.original_greeny = $.fn.greenify;

    // provide a wrapper
    $.fn.myFunction = function () {
        // the jquery elements for applying later
        var $this = $(this)

        // exported function
        return {
            greenify: function() {
                // Call the original function with the jquery elements
                // and return them for chaining
                return me.original_greeny.apply($this)
            }
        };

    };
})(jQuery);

// Now remove the original completely
(function ( $ ) {
    $.fn.greenify = null;
}(jQuery));

// As desired, also demonstrating chaining still works
$("#a").myFunction().greenify().css("font-style", "italic")

// Confirm that the original has been removed 
// gives error $(...).greenify is not a function
try {
  $("#a").greenify()
} catch(e) {
  $("#a").text("error on $().greenify: " + e)
}

和一个jsfiddle