A template for a jQuery plugin with options and accessible methods?

前端 未结 4 984
名媛妹妹
名媛妹妹 2021-02-10 05:57

I am want to build a plugin with accessible methods and options, this for a complex plugin. I need the methods to be accessible outside the plugin because if somebody ads someth

相关标签:
4条回答
  • 2021-02-10 06:22

    If you want to use the plugin like this:

    // Init plugin
    $('a').myplugin({
        color: 'blue'
    });
    
    // Call the changeBG method
    $('a').myplugin('changeBG')
        // chaining
        .each(function () {
            // call the get method href()
            console.log( $(this).myplugin('href') );
        });
    

    or if you need independent Plugin instance per element:

    $('a').each(function () {
        $(this).myplugin();
    });
    

    you will want to setup your plugin like this:

    /*
     *  Project: 
     *  Description: 
     *  Author: 
     *  License: 
     */
    
    // the semi-colon before function invocation is a safety net against concatenated
    // scripts and/or other plugins which may not be closed properly.
    ;(function ( $, window, document, undefined ) {
    
        // undefined is used here as the undefined global variable in ECMAScript 3 is
        // mutable (ie. it can be changed by someone else). undefined isn't really being
        // passed in so we can ensure the value of it is truly undefined. In ES5, undefined
        // can no longer be modified.
    
        // window is passed through as local variable rather than global
        // as this (slightly) quickens the resolution process and can be more efficiently
        // minified (especially when both are regularly referenced in your plugin).
    
        var pluginName = "myplugin",
            // the name of using in .data()
            dataPlugin = "plugin_" + pluginName,
            // default options
            defaults = {
                color: "black"
            };
    
        function privateMethod () {
            console.log("private method");
        }
    
        // The actual plugin constructor
        function Plugin() {
            /*
             * Plugin instantiation
             *
             * You already can access element here
             * using this.element
             */
             this.options = $.extend( {}, defaults );
        }
    
        Plugin.prototype = {
    
            init: function ( options ) {
    
                // extend options ( http://api.jquery.com/jQuery.extend/ )
                $.extend( this.options, options );
    
                /*
                 * Place initialization logic here
                 */
                this.element.css( 'color', 'red' );
            },
    
            destroy: function () {
                // unset Plugin data instance
                this.element.data( dataPlugin, null );
            },
    
            // public get method
            href: function () {
                return this.element.attr( 'href' );
            },
    
            // public chaining method
            changeBG: function ( color = null ) {
                color = color || this.options['color'];
                return this.element.each(function () {
                    // .css() doesn't need .each(), here just for example
                    $(this).css( 'background', color );
                });
            }
        }
    
        /*
         * Plugin wrapper, preventing against multiple instantiations and
         * allowing any public function to be called via the jQuery plugin,
         * e.g. $(element).pluginName('functionName', arg1, arg2, ...)
         */
        $.fn[pluginName] = function ( arg ) {
    
            var args, instance;
    
            // only allow the plugin to be instantiated once
            if (!( this.data( dataPlugin ) instanceof Plugin )) {
    
                // if no instance, create one
                this.data( dataPlugin, new Plugin( this ) );
            }
    
            instance = this.data( dataPlugin );
    
            /*
             * because this boilerplate support multiple elements
             * using same Plugin instance, so element should set here
             */
            instance.element = this;
    
            // Is the first parameter an object (arg), or was omitted,
            // call Plugin.init( arg )
            if (typeof arg === 'undefined' || typeof arg === 'object') {
    
                if ( typeof instance['init'] === 'function' ) {
                    instance.init( arg );
                }
    
            // checks that the requested public method exists
            } else if ( typeof arg === 'string' && typeof instance[arg] === 'function' ) {
    
                // copy arguments & remove function name
                args = Array.prototype.slice.call( arguments, 1 );
    
                // call the method
                return instance[arg].apply( instance, args );
    
            } else {
    
                $.error('Method ' + arg + ' does not exist on jQuery.' + pluginName);
    
            }
        };
    
    }(jQuery, window, document));
    

    Notes:

    • This boilerplate will not use .each() for every method call, you should use .each() when you need
    • Allow re-init plugin, but only 1 instance will be created
    • Example of destroy method is included

    Ref: https://github.com/jquery-boilerplate/jquery-boilerplate/wiki/jQuery-boilerplate-and-demo

    0 讨论(0)
  • 2021-02-10 06:29

    An alternative:

    var Plugin = function($self, options) {
      this.$self = $self;
      this.options = $.extend({}, $.fn.plugin.defaults, options);
    };
    
    Plugin.prototype.display = function(){
      console.debug("Plugin.display");
    };
    
    Plugin.prototype.update = function() {
      console.debug("Plugin.update");
    };
    
    $.fn.plugin = function(option) {
      var options = typeof option == "object" && option;
    
      return this.each(function() {
        var $this = $(this);
        var $plugin = $this.data("plugin");
    
        if(!$plugin) {
          $plugin = new Plugin($this, options);
          $this.data("plugin", $plugin);
        }
    
        if (typeof option == 'string') {
          $plugin[option]();
        } else {
          $plugin.display();
        }
      });
    };
    
    $.fn.plugin.defaults = {
      propname: "propdefault"
    };
    

    Usage:

    $("span").plugin({
      propname: "propvalue"
    });
    

    $("span").plugin("update");
    

    This absurdly resembles the Twitter Bootstrap's JavaScript template. But, it wasn't completely taking from there. I have a long history of using .data().

    Don't forget to wrap it appropriately.

    0 讨论(0)
  • 2021-02-10 06:36

    Have you tried the jQuery UI Widget Factory?

    There was a bit of a learning curve, but I love it now, handle the options, and defaults and allows methods, keeps everything wrapped up tight very fancy :)


    EDIT

    The jQuery UI Widget Factory is a separate component of the jQuery UI Library that provides an easy, object oriented way to create stateful jQuery plugins.

    – Introduction to Stateful Plugins and the Widget Factory.

    I don't think the extra overhead is much to be worried about in most circumstances. These days I write in coffescript and everything is compiled, minified and gzipped, so a few extra lines here and there doesn't make much of a difference. My research in website speed seems to indicate that the number of HTTP requests is a big deal - indeed the former colleague that put me on this track worked for a browser based game and was all about speed speed speed.

    0 讨论(0)
  • 2021-02-10 06:41

    Here is the latest boilerplate https://github.com/techlab/jquery-plugin-boilerplate

    Also you can use the create-jquery-plugin npm CLI utility. just run

    npx create-jquery-plugin
    
    0 讨论(0)
提交回复
热议问题