Plantilla para plugins jQuery

27 Abr 2011

Vía Stefan Gabos encuentro una plantilla muy completa y útil para desarrolladores de plugins jQuery: se trata de un boilerplate perfectamente estructurado que puede servir de esquema para cualquier tipo de extensión que queramos programar para esta popular librería biblioteca.

Las características de esta plantilla son las siguientes:

  • Prevenir errores originados por implementaciones en proyectos pobres.
  • Establecer opciones por defecto al plugin.
  • Estructura prediseñada para métodos públicos (API del plugin).
  • Estructura prediseñada para métodos privados.
  • Comprobación de que un determinado método invocado existe y es aplicable.


NOTA: En la versión comentada de la plantilla tenéis detallada cada una de las características anteriores.

El código de la plantilla queda así:

// remember to change every instance of "pluginName"
// to the name of your plugin!
;(function($) {
 
    // here it goes!
    $.fn.pluginName = function(method) {
 
        // plugin's default options
        var defaults = {
 
            foo: 'bar'
 
        }
 
        // this will hold the merged default and user-provided properties
        // you will have to access the plugin's properties through this object!
        // settings.propertyName
        var settings = {}
 
        // public methods
        // to keep the $.fn namespace uncluttered, collect all
        // of the plugin's methods in an object literal and call
        // them by passing the string name of the method to the plugin
        //
        // public methods can be called as
        // $(selector).pluginName('methodName', arg1, arg2, ... argn)
        // where "pluginName" is the name of your plugin and "methodName"
        //is the name of a function available in
        // the "methods" object below;
        // arg1 ... argn are arguments to be passed to the method
        //
        // or, from within the plugin itself, as
        // methods.methodName(arg1, arg2, ... argn)
        // where "methodName" is the name of a function available
        // in the "methods" object below
        var methods = {
 
            // this the constructor method that gets called when
            // the object is created
            init : function(options) {
 
                // iterate through all the DOM elements we are
                // attaching the plugin to
                return this.each(function() {
 
                    // the plugin's final properties are the merged default
                    // and user-provided properties (if any)
                    // this has the advantage of not polluting the defaults,
                    // making the same instace re-usable with
                    // new options; thanks to Steven Black for suggesting this
                    settings = $.extend({}, defaults, options)
 
                    // "element" holds the jQuery object of the current DOM element
                    var element = $(this);
 
                    // code goes here
 
                });
 
            },
 
            // a public method. for demonstration purposes only - remove it!
            foo_public_method: function() {
 
                // code goes here
 
            }
 
        }
 
        // private methods
        // these methods can be called only from within the plugin
        //
        // private methods can be called as
        // helpers.methodName(arg1, arg2, ... argn)
        // where "methodName" is the name of a function available in
        // the "helpers" object below; arg1 ... argn are arguments to
        // be passed to the method
        var helpers = {
 
            // a private method. for demonstration purposes only - remove it!
            foo_private_method: function() {
 
                // code goes here
 
            }
 
        }
 
        // if a method as the given argument exists
        if (methods[method]) {
 
            // call the respective method
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
 
        // if an object is given as method OR nothing is given as argument
        } else if (typeof method === 'object' || !method) {
 
            // call the initialization method
            return methods.init.apply(this, arguments);
 
        // otherwise
        } else {
 
            // trigger an error
            $.error( 'Method "' +  method + '" does not exist in pluginName plugin!');
 
        }
 
    }
 
})(jQuery);

Si preferimos una versión sin comentarios más ligera y manejable:

;(function($) {
 
    $.fn.pluginName = function(method) {
 
        var defaults = {
            foo: 'bar'
        }
 
        var settings = {}
 
        var methods = {
 
            init : function(options) {
                return this.each(function() {
                    settings = $.extend({}, defaults, options)
                    var element = $(this);
                    // code goes here
                });
            },
 
            foo_public_method: function() {
                // code goes here
            }
 
        }
 
        var helpers = {
 
            foo_private_method: function() {
                // code goes here
            }
 
        }
 
        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 in pluginName plugin!');
        }
 
    }
 
})(jQuery);

NOTA: Si os preguntáis qué significa el punto y coma (;) de la primera línea, su función es prevenir errores heredados de un código anterior. Un pequeño truco que resulta siempre útil cuando creamos extensiones o submódulos en archivos independientes.

En la documentación oficial de jQuery, podemos encontrar otras estructuras interesantes para la creación de plugins. Sin embargo, no hacen distinción o separación entre los métodos públicos y privados por lo que el código final puede resultar algo confuso de mantener.

Tenéis toda la información y ejemplos aquí.

En una próxima entrega utilizaremos esta plantilla para crear un plugin sencillo y estudiar su estructura más en detalle.

Hasta ese momento, si surjen preguntas, no dudéis en usar los comentarios.

Más:

{2} Comentarios.

  1. guzman

    Para mi que esta parte:

                init : function(options) {
                    return this.each(function() {
                        settings = $.extend({}, defaults, options)
                        var element = $(this);
                        // code goes here
                    });
                },
    

    debería de ser así:

                init : function(options) {
                        // extender el objeto de parametors
                        settings = $.extend({}, defaults, options) ;            
                        // iterar entre los elementos
                         return this.each(function() {
                        var element = $(this);
                        // code goes here
                    });
                },
    

    Más que nada porque si no estamos haciendo el extend una vez por cada elemento de la colección.
    Y puede haber muuuuchos…

  2. aanton

    Hola!

    Stefan Gabos ha actualizado la plantilla (7/mayo):
    http://stefangabos.ro/jquery/jquery-plugin-boilerplate/

    Y ha creado una versión diferente:
    http://stefangabos.ro/jquery/jquery-plugin-boilerplate-revisited/

    Copio sus palabras acerca de esta versión diferente:

    Also, a different approach (http://stefangabos.ro/jquery/jquery-plugin-boilerplate-revisited/) for the jQuery Plugin Boilerplate is now available, an approach that does not adhere to the suggestions made by the jQuery documentation regarding Plugins/Authoring (http://docs.jquery.com/Plugins/Authoring) and that is more OOP.

    For this new version of the jQuery Plugin Boilerplate, I took inspiration from Doug Neiner‘s Starter (http://jquery.codestarters.com/) which I find to be a more appropriate way of writing a jQuery plugin

    Saludos!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *