jQuery插件模板 - 最佳实践,约定,性能和内存影响

时间:2011-05-12 15:10:42

标签: javascript jquery jquery-plugins

我已经开始编写一些jQuery插件,并认为使用jQuery插件模板设置我的IDE会很不错。

我一直在阅读本网站上与插件约定,设计等相关的一些文章和帖子。并且我认为我会尝试巩固所有这些。

下面是我的模板,我希望经常使用它,所以很想确保它通常符合jQuery插件设计约定以及是否有多个内部方法(甚至是它的一般设计)的想法会影响性能并且容易发生记忆问题。

(function($)
{
    var PLUGIN_NAME = "myPlugin"; // TODO: Plugin name goes here.
    var DEFAULT_OPTIONS =
    {
        // TODO: Default options for plugin.
    };
    var pluginInstanceIdCount = 0;

    var I = function(/*HTMLElement*/ element)
    {
        return new Internal(element);
    };

    var Internal = function(/*HTMLElement*/ element)
    {
        this.$elem = $(element);
        this.elem = element;
        this.data = this.getData();

        // Shorthand accessors to data entries:
        this.id = this.data.id;
        this.options = this.data.options;
    };

    /**
     * Initialises the plugin.
     */
    Internal.prototype.init = function(/*Object*/ customOptions)
    {
        var data = this.getData();

        if (!data.initialised)
        {
            data.initialised = true;
            data.options = $.extend(DEFAULT_OPTIONS, customOptions);

            // TODO: Set default data plugin variables.
            // TODO: Call custom internal methods to intialise your plugin.
        }
    };

    /**
     * Returns the data for relevant for this plugin
     * while also setting the ID for this plugin instance
     * if this is a new instance.
     */
    Internal.prototype.getData = function()
    {
        if (!this.$elem.data(PLUGIN_NAME))
        {
            this.$elem.data(PLUGIN_NAME, {
                id : pluginInstanceIdCount++,
                initialised : false
            });
        }

        return this.$elem.data(PLUGIN_NAME);
    };

    // TODO: Add additional internal methods here, e.g. Internal.prototype.<myPrivMethod> = function(){...}

    /**
     * Returns the event namespace for this widget.
     * The returned namespace is unique for this widget
     * since it could bind listeners to other elements
     * on the page or the window.
     */
    Internal.prototype.getEventNs = function(/*boolean*/ includeDot)
    {
        return (includeDot !== false ? "." : "") + PLUGIN_NAME + "_" + this.id;
    };

    /**
     * Removes all event listeners, data and
     * HTML elements automatically created.
     */
    Internal.prototype.destroy = function()
    {
        this.$elem.unbind(this.getEventNs());
        this.$elem.removeData(PLUGIN_NAME);

        // TODO: Unbind listeners attached to other elements of the page and window.
    };

    var publicMethods =
    {
        init : function(/*Object*/ customOptions)
        {
            return this.each(function()
            {
                I(this).init(customOptions);
            });
        },

        destroy : function()
        {
            return this.each(function()
            {
                I(this).destroy();
            });
        }

        // TODO: Add additional public methods here.
    };

    $.fn[PLUGIN_NAME] = function(/*String|Object*/ methodOrOptions)
    {
        if (!methodOrOptions || typeof methodOrOptions == "object")
        {
            return publicMethods.init.call(this, methodOrOptions);
        }
        else if (publicMethods[methodOrOptions])
        {
            var args = Array.prototype.slice.call(arguments, 1);

            return publicMethods[methodOrOptions].apply(this, args);
        }
        else
        {
            $.error("Method '" + methodOrOptions + "' doesn't exist for " + PLUGIN_NAME + " plugin");
        }
    };
})(jQuery);

提前致谢。

4 个答案:

答案 0 :(得分:28)

前段时间我根据我读过的博客文章构建了一个插件生成器:http://jsfiddle.net/KeesCBakker/QkPBF/。它可能有用。这是相当基本和直接的。任何评论都会非常受欢迎。

您可以分叉自己的发电机并根据需要进行更改。

聚苯乙烯。这是生成的正文:

(function($){

    //My description
    function MyPluginClassName(el, options) {

        //Defaults:
        this.defaults = {
            defaultStringSetting: 'Hello World',
            defaultIntSetting: 1
        };

        //Extending options:
        this.opts = $.extend({}, this.defaults, options);

        //Privates:
        this.$el = $(el);
    }

    // Separate functionality from object creation
    MyPluginClassName.prototype = {

        init: function() {
            var _this = this;
        },

        //My method description
        myMethod: function() {
            var _this = this;
        }
    };

    // The actual plugin
    $.fn.myPluginClassName = function(options) {
        if(this.length) {
            this.each(function() {
                var rev = new MyPluginClassName(this, options);
                rev.init();
                $(this).data('myPluginClassName', rev);
            });
        }
    };
})(jQuery);

答案 1 :(得分:26)

答案 2 :(得分:0)

我一直在谷歌上搜索,所以,我必须发表一些想法:首先我同意@Raynos。

那里试图构建jQuery插件的代码最多......不是插件!它只是存储在内存中的一个对象,它由节点/元素的data属性引用。这是因为应该看到jQuery并将其作为一个工具与一个类库一起使用(以补救来自OO架构的js不一致)来构建更好的代码,是的,这一点都不错!

如果您不喜欢古典OO行为,请坚持使用像clone这样的原型库。

那么我们的选择到底是什么?

  • 使用JQueryUI / Widget或隐藏技术细节的类似库 提供抽象
  • 不要因为复杂性而使用它们,学习曲线和上帝知道未来的变化
  • 不要使用它们,因为你想坚持模块化设计,后来建立小增加
  • 不要使用它们,因为您可能希望使用不同的库移植/连接代码。

假设以下方案解决了问题(请参阅此问题的复杂性:Which jQuery plugin design pattern should I use?):

  

我们有节点A,B和C,它们将对象引用存储到data属性

中      
    

其中一些将信息存储在公共私人可访问的 内部对象 中,     这些对象的某些类与继承相关联,     所有这些节点还需要一些私有的公共 单例 才能发挥最佳效果。

  

我们会怎么做?见图:

classes : |  A        B         C
------------------case 1----------
members   |  |        |         |
  of      |  v        v         v
an object | var a=new A, b=new B,  c=new C
  at      |     B extends A
node X :  |  a, b, c : private
------------------case 2---------
members   |  |        |         |
  of      |  v        v         v
an object | var aa=new A, bb=new B, cc=new C
  at      |     BB extends AA
node Y :  |  aa, bb, cc : public
-------------------case 3--------
members   |  |        |         |
  of      |  v        v         v
an object | var d= D.getInstance() (private),
  at      |     e= E.getInstance() (public)
node Z :  |     D, E : Singletons

正如你所看到的,每个节点都引用一个对象 - 一个jQuery方法 - 但是这些对象变化很大;它们包含存储在其中的不同数据的对象属性,甚至单个内存应该是...单个内存,就像对象的原型函数一样。我们不希望属于class A的每个对象的函数在每个节点的对象中重复 在内存中重复

在我回答之前 看到我在jQuery插件中看到的一种常见方法 - 其中一些非常受欢迎,但我不说名字:

(function($, window, document, undefined){
   var x = '...', y = '...', z = '...',
       container, $container, options;
   var myPlugin = (function(){ //<----the game is lost!
      var defaults = {

      };
      function init(elem, options) {
         container = elem;
         $container = $(elem);
         options = $.extend({}, defaults, options);
      }
      return {
         pluginName: 'superPlugin',
         init: function(elem, options) {
            init(elem, options);
         }
      };
   })();
   //extend jquery
   $.fn.superPlugin = function(options) {
      return this.each(function() {
         var obj = Object.create(myPlugin); //<---lose, lose, lose!
         obj.init(this, options);
         $(this).data(obj.pluginName, obj);
      });
   };

}(jQuery, window, document));

我正在观看Ben Benman的http://www.slideshare.net/benalman/jquery-plugin-creation处的一些幻灯片,他在第13张幻灯片中将 对象文字 称为 单身人士< / em> ,这只是让我失望:这就是上面的插件所做的,它创建了一个单独的 没有机会 来改变它的内部状态! !!

此外,在jQuery部分,它将 公共引用 存储到每个节点!

我的解决方案使用 工厂 来保持内部状态并返回一个对象,并且可以使用 类扩展 库并拆分成不同的文件:

;(function($, window, document, undefined){
   var myPluginFactory = function(elem, options){
   ........
   var modelState = {
      options: null //collects data from user + default
   };
   ........
   function modeler(elem){
      modelState.options.a = new $$.A(elem.href);
      modelState.options.b = $$.B.getInstance();
   };
   ........
   return {
         pluginName: 'myPlugin',
         init: function(elem, options) {
            init(elem, options);
         },
         get_a: function(){return modelState.options.a.href;},
         get_b: function(){return modelState.options.b.toString();}
      };
   };
   //extend jquery
   $.fn.myPlugin = function(options) {
      return this.each(function() {
         var plugin = myPluginFactory(this, options);
         $(this).data(plugin.pluginName, plugin);
      });
   };
}(jQuery, window, document));

我的项目:https://github.com/centurianii/jsplugin

请参阅:http://jsfiddle.net/centurianii/s4J2H/1/

答案 3 :(得分:0)

这样的事情怎么样?它更加清晰但是如果你能够改进它而不会过于复杂,那么很高兴听到你。

// jQuery plugin Template
(function($){
    $.myPlugin = function(options) { //or use "$.fn.myPlugin" or "$.myPlugin" to call it globaly directly from $.myPlugin();
        var defaults = {
            target: ".box",
            buttons: "li a"             
        };

        options = $.extend(defaults, options);

        function logic(){
            // ... code goes here
        }

        //DEFINE WHEN TO RUN THIS PLUGIN
        $(window).on('load resize', function () { // Load and resize as example ... use whatever you like
            logic();
        });

        // RETURN OBJECT FOR CHAINING
        // return this;

        // OR FOR FOR MULTIPLE OBJECTS
        // return this.each(function() {
        //    // Your code ...
        // });

    };
})(jQuery);


// USE EXAMPLE with default settings
$.myPlugin(); // or run plugin with default settings like so.

// USE EXAMPLE with overwriten settings
var options = {
    target: "div.box", // define custom options
    buttons: ".something li a" // define custom options
}     
$.myPlugin(options); //or run plugin with overwriten default settings