【问题标题】:Writing jQuery Plugins Using Classes and Prototypes使用类和原型编写 jQuery 插件
【发布时间】:2026-01-22 22:45:02
【问题描述】:

以这种方式(使用类和原型)编写插件是好还是坏,这段代码有什么缺点?

function PluginName(jqueryObject, options) {

}
PluginName.prototype = {
    publicMethod:function() {
    },
    _privateMethod:function() {
    }
}

// Initializing 
var myPluginInstance = new PluginName($(".mySelector"), {myOption:1});
myPluginInstance.publicMethod();

【问题讨论】:

  • 这两种方法都是公开的,或者可以通过此代码访问。
  • 缺点:不能使用jQuery的流畅界面。
  • 谢谢,那么在这里声明私有方法的最佳方式是什么?

标签: javascript jquery plugins


【解决方案1】:

请参阅jQuery docs on plugin authoring 了解最佳做法:

  • 始终将您的插件包装在(function( $ ){ // plugin goes here })( jQuery );
  • 不要在插件函数的直接范围内过多地包装 this 关键字
  • 除非您从插件返回一个内在价值,否则请始终让您的插件函数返回 this 关键字以保持可链接性。
  • 与其需要大量的参数,不如将您的插件设置传递到可以扩展插件默认值的对象字面量中。
  • 不要将 jQuery.fn 对象与每个插件的多个命名空间混为一谈。
  • 始终为您的方法、事件和数据命名。

示例

(function( $ ){

  var methods = {
    init : function( options ) { // THIS },
    show : function( ) { // IS   },
    hide : function( ) { // GOOD },
    update : function( content ) { // !!! }
  };

  $.fn.tooltip = function( method ) {

    // Method calling logic
    if ( methods[method] ) {
      return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist on jQuery.tooltip' );
    }    

  };

})( jQuery );

用法:

$('div').tooltip(); // calls the init method
$('div').tooltip({  // calls the init method
  foo : 'bar'
});
$('div').tooltip('hide'); // calls the hide method
$('div').tooltip('update', 'This is the new tooltip content!'); // calls the update method

默认值和选项示例

(function( $ ){

  $.fn.tooltip = function( options ) {  

    var settings = {
      'location'         : 'top',
      'background-color' : 'blue'
    };

    return this.each(function() {        
      // If options exist, lets merge them
      // with our default settings
      if ( options ) { 
        $.extend( settings, options );
      }

      // Tooltip plugin code here

    });

  };
})( jQuery );

用法:

$('div').tooltip({
  'location' : 'left'
});

【讨论】:

  • 方法之间如何共享数据?
【解决方案2】:

首先,正如 Spycho 所说,始终将插件包装在

(function( $ ){
    $.fn.PluginName = function() {
        // plugin goes here
    };
})( jQuery );

避免与使用美元符号的其他库发生冲突。

其次,如果您扩展jQuery.fn 对象,则使用$("#myDiv") 之类的名称调用的选择将作为this 传递给插件。这样您就不必像以前那样将选择作为参数传递给插件。

第三,你做对了,他们建议你将选项作为一个对象而不是单个参数传递给插件,这样你就可以轻松地拥有和覆盖默认值:

(function( $ ){
    $.fn.PluginName = function(options) {
        var settings = { myOption: 1 };
        if (options) {
            $.extend( settings, options );
        }
        // plugin goes here
    };
})( jQuery );

第四,您创建 _privateMethod 的方式实际上并没有将其设为私有,为此您可以遵循 jQuery 在 plugin authoring guidelines 中建议的模式

(function( $ ){
    var methods = {
        publicMethod: function(options) {
           var settings = { myOption: 1 };
            if (options) {
                $.extend( settings, options );
            }
        },
        _privateMethod: function() {}            
    }
    $.fn.PluginName = function(methodName, options) {
        // use some logic to control what methods are public
        if (methodName == "publicMethod") {
            return publicMethod.apply(this, Array.prototype.slice.call( arguments, 1 ));
        }
    };
})( jQuery );

这使用了applycall,它们是用于设置函数调用范围的花哨的内置函数方法,请参阅MDN reference 以了解那里发生了什么。通过这种方式,您实际上可以控制哪些方法是公共的还是私有的。

编辑: 最后,如果你想完全维护 jQuery 的流畅界面,并且让你的插件都接受$() 传递的选择并将其传递,换句话说,是可链接的,你的方法需要返回给定对象的集合:

(function( $ ){
    var methods = {
        publicMethod: function(options) {
           var settings = { myOption: 1 };
            if (options) {
                $.extend( settings, options );
            }
            return this.each(function() {
                this.value = (this.value * 1) + settings.myOption;
            });
        },
        _privateMethod: function() {}            
    }
    $.fn.PluginName = function(methodName, options) {
        // use some logic to control what methods are public
        if (methodName == "publicMethod") {
            return methods.publicMethod.apply(this, Array.prototype.slice.call( arguments, 1 ));
        }
    };
})( jQuery );

查看jsFiddle 了解最终工作示例。

【讨论】:

    【解决方案3】:

    编写 jQuery 插件(尤其是如果它们有一些内部状态)最简单的方法是使用 jQuery UI Widget Factory。

    我不建议自己重新发明*并编写大量样板代码。

    https://learn.jquery.com/jquery-ui/widget-factory/why-use-the-widget-factory/ https://learn.jquery.com/plugins/stateful-plugins-with-widget-factory/

    【讨论】:

      最近更新 更多