Summary of the five forms of jQuery plug in development

  • 2020-05-10 17:39:10
  • OfStack

I have done a little research on the development of the jQuery plug-in, wrote several plug-ins, and Shared a lesson about the plug-in with my team. What started out as very complex code is now much clearer when you look at it again. Here I share what I've learned to help others who have faced the same problems as me.

What am I going to do
The javascript plug-in I want should have the following characteristics

Code independence
The chain operation
Plug-in configurable
There are actionable methods that control the plug-in's lifecycle
The configuration can be cached
extensible
Conflict-free handling
Event proxy, dynamic initialization

* the following code assumes the existence of jQuery

The first form of the plug-in

Faced with this situation, we usually do this by defining function.


function pluginName($selector){
    $.each($selector, function () {
        $(this).css("background-color", "#ccc");
        // to do something...
    });
}
// pluginName(document.getElementsByClassName("demo"));

Since I am talking about jQuery plug-in development, I will now extend this code to jQuery as follows:


// IIFE( Call the function expression immediately );  [ reference http://suqing.iteye.com/blog/1981591/]
;(function ($) {
    // Extend this method to jQuery.
    // $.extend() Right? The method extends to $ Object, and $.fn.extend Different. Extended to $.fn.xxx After the,
    // It can be when it's called $(selector).xxx()
    $.fn.extend({
        // The plugin name
        pluginName: function () {
            // Traverses the collection of matched elements
            // Notice there's one here "return" , is to return the object after processing, to achieve chain operation
            return this.each(function () {
                // This is where you write the code to handle it
            });
        }
    });
// pass jQuery Go to the inner scope , if window,document Use a lot of words , You can also pass it in here .
// })(jQuery, window, document, undefined);
})(jQuery, undefined);
// Call way $(".selector").pluginName().otherMethod();

But there is still a long way to go. So far only two problems have been solved

Code independence
The chain operation
Plug-in configurable
There are actionable methods that control the plug-in's lifecycle
The configuration can be cached
extensible
Conflict-free handling
Event proxy, dynamic initialization

The second form of the plug-in

Now add parameter support to the plug-in. The following code


;(function($){
    $.fn.pluginName = function(options) {
        // Merge parameters by" extend "Merge default and custom parameters
        var args = $.extend({}, $.fn.pluginName.defaults, options);
        return this.each(function() {
            console.log(args.text);
            // to do something...
        });
    };
    // The default parameters
    $.fn.pluginName.defaults = {
        text : "hello"
    };
})(jQuery);
// $(".selector").pluginName({
//     text : "hello world!"
// });

It is easier to add parameter support, which solves the 1 problem

Code independence
The chain operation
Plug-in configurable
There are actionable methods that control the plug-in's lifecycle
The configuration can be cached
extensible
Conflict-free handling
Event proxy, dynamic initialization

The third form of the plug-in

Now let's add method support. I mentioned earlier that the lifecycle is controllable, which means something like adding reInit,destory, and so on to control the plug-in.


;(function($){
    $.fn.pluginName = function (method) {
        // If the first 1 Two parameters are strings , Just find out if the method exists , Find and call ; If it is object object , Just call init methods ;.
        if (methods[method]) {
            // The method is called if it exists
            // apply Isn't it obj.method(arg1, arg2, arg3) Converted to method(obj, [arg1, arg2, arg3]) The process of .
            // Array.prototype.slice.call(arguments, 1) Is to convert the method's arguments to an array .
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            // If the parameter passed in is "{...}", It's considered an initialization operation .
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method ' + method + ' does not exist on jQuery.pluginName');
        }
    };
    // Do not extend the method in $.fn.pluginName on . Build one inside the closure "methods" To save the method , Similar common methods .
    var methods = {
        /**
         * Initialization method
         * @param _options
         * @return {*}
         */
        init : function (_options) {
            return this.each(function () {
                var $this = $(this);
                var args = $.extend({}, $.fn.pluginName.defaults, _options);
                // ...
            })
        },
        publicMethod : function(){
            private_methods.demoMethod();
        }
    };
    // Private methods
    function private_methods = {
        demoMethod : function(){}
    }
    // The default parameters
    $.fn.pluginName.defaults = {
    };
})(jQuery);
// Call way
// $("div").pluginName({...});  // Initialize the
// $("div").pluginName("publicMethod");  // A method is called

Problem number one

Code independence
The chain operation
Plug-in configurable
There are actionable methods that control the plug-in's lifecycle
The configuration can be cached
extensible
Conflict-free handling
Event proxy, dynamic initialization

The fourth form of the plug-in

Plug-in modifications in the third form can already address the needs of most plug-ins. Keep upgrading.
The plug-in in the fourth form is based on the code of javascript framework designed by situ zhengmei. A little bit of object-oriented knowledge.


(function ($) {
    var Plugin = function (element, options) {
        this.element = element;
        this.options = options;
    };
    Plugin.prototype = {
        create: function () {
            console.log(this.element);
            console.log(this.options);
        }
    };
    $.fn.pluginName = function (options) {
        // Consolidation parameters
        return this.each(function () {
            // This is where you write the code to handle it
            var ui = $._data(this, "pluginName");
            // If the element is not initialized ( It could be a newly added element ), I'm going to initialize it .
            if (!ui) {
                var opts = $.extend(true, {}, $.fn.pluginName.defaults, typeof options === "object" ? options : {});
                ui = new Plugin(this, opts);
                // Cache plug-in
                $._data(this, "pluginName", ui);
            }
            // A method is called
            if (typeof options === "string" && typeof ui[options] == "function") {
                // Method to execute the plug-in
                ui[options].apply(ui, args);
            }
        });
    };
    $.fn.pluginName.defaults = {};
})(jQuery);
// How and before the call 1 The sample.

Here especially to mention the cache this thing, plug-in used more, feel this is really a good thing.
In traditional object-oriented plug-in development, you would declare at least one variable to hold it, but none of the jQuery plug-ins I've written so far have it, and it's a pain to use. Since the initial plug-in is cached, it is much easier. You can fetch the object with the code $("#target").data("pluginName"). Let's see if there are any problems left

Code independence
The chain operation
Plug-in configurable
There are actionable methods that control the plug-in's lifecycle
The configuration can be cached
extensible
Conflict-free handling
Event proxy, dynamic initialization

The fifth form of the plug-in

See if the above code is a little dizzy, if so, take a short break, come back later, the following code is more exciting. The last one is quite comprehensive. The scheme comes from Bootstrap, and the following code takes the button plug-in of Bootstrap as an example.


!function ($) {
    // ecma262v5 The new things , Enforce strict coding .
    "use strict";
    // BUTTON PUBLIC CLASS DEFINITION
    // ==============================
    var Button = function (element, options) {
        this.$element = $(element);
        this.options = $.extend({}, Button.DEFAULTS, options);
    };
    Button.DEFAULTS = {
        loadingText: 'loading...'
    };
    Button.prototype.setState = function (state) {
        // ...
    };
    Button.prototype.toggle = function () {
        // ...
    };
    // BUTTON PLUGIN DEFINITION
    // ========================
    var old = $.fn.button; // Here, $.fn.button It may be a plug-in that has been defined before and is used here for conflict-free handling.
    $.fn.button = function (option) {
        return this.each(function () {
            var $this = $(this);
            // The basis for determining whether or not initialization has been performed
            var data = $this.data('bs.button');
            var options = typeof option == 'object' && option;
            // If it's not initialized , I'm going to initialize it
            if (!data) $this.data('bs.button', (data = new Button(this, options)));
            if (option == 'toggle') data.toggle();
            else if (option) data.setState(option)
        })
    };
    // 1. Exposure to the name of the class , You can use this to customize extensions for your plug-in
    $.fn.button.Constructor = Button;
    // Extended way
    // Set up the : $.fn.button.Constructor.newMethod = function(){}
    // use : $btn.button("newMethod");
    // 2. Conflict-free handling
    $.fn.button.noConflict = function () {
        $.fn.button = old;
        return this
    };
    // 3. The event agent , Intelligent initialization
    $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) {
        var $btn = $(e.target);
        // Find the object to initialize
        if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn');
        // Call method directly , If it's not initialized , Internally, it initializes first
        $btn.button('toggle');
        e.preventDefault();
    });
}(jQuery);

Let's see if there are any problems left

Code independence
The chain operation
Plug-in configurable
There are actionable methods that control the plug-in's lifecycle
The configuration can be cached
extensible
Conflict-free handling
Event proxy, dynamic initialization

supplement

Today's plug-ins require a lot of flexibility, such as the ability to accommodate both jQuery and Zepto, or the need to support the AMD or CMD specifications.

jQuery and Zepto are supported


if (window.jQuery || window.Zepto) {
  (function ($) {
      // plugin code...
  })(window.jQuery || window.Zepto);
}

Middleware support, node


if (typeof(module) !== 'undefined')
{
  module.exports = pluginName;
}
requirejs(AMD) support
if (typeof define === 'function' && define.amd) {
  define([], function () {
      'use strict';
      return pluginName;
  });
}
seajs(CMD) support
if (typeof define === 'function') {
  define([], function () {
      'use strict';
      return pluginName;
  });
}

Call ~, the problem has been solved, the code if there is not understand the place can see more. It doesn't matter if you don't understand the last few. In actual development, the first few are enough. It should be stressed that it is not better to write in a more advanced way, but to make a reasonable choice based on the requirements of your own project.

Well, that's the end of today's summary, if you have a better way of plug-in development, please let me know 1. I hope you enjoyed this article.


Related articles: