jquery Plug-in development model
jquery Plug-ins typically have three ways of developing:
- Extend jquery through $.extend ()
- Adding new methods to jquery via $.fn
- Creating a part Factory by $.widget () applying the jquery UI
The first type of $.extend () is relatively simple, generally rarely able to independently develop complex plug-ins, the third is a high-level development model, this article does not introduce. The second is the way of general plug-in development, this article focuses on the second.
Plug-in development
The second type of plug-in development method is generally defined as
$.fn.pluginname = function () {
//your code here
}
Plug-in development, we generally use the object-oriented way of thinking
For example, to define an object
var haorooms= function (el, opt) {this
. $element = el,
this.defaults = {
' color ': ' Red ',
' fontsize ': ' 12px ',
' textdecoration ': ' None '
},
this.options = $.extend ({}, this.defaults, opt)
}
// The method that defines haorooms
Haorooms.prototype = {
changecss:function () {return this
. $element. css ({
' color ' : This.options.color,
' fontsize ': this.options.fontSize,
' textdecoration ': this.options.textDecoration
});
}
}
$.extend ({}, this.defaults, opt) has {} Primarily to create a new object, preserving the object's default value.
$.fn.myplugin = function (options) {
//create haorooms entity
var haorooms= new Haorooms (this, options);
Call its method return
haorooms.changecss ();
}
Call this plugin directly as follows
$ (function () {
$ (' a '). Myplugin ({
' color ': ' #2C9929 ', '
fontsize ': ' 20px '
})
The problem of the above development method
The above development method has a serious problem, is to define a global haorooms, so that the compatibility of plug-ins and so on all aspects are not good. In case other place uses the haorooms, then your code is sad urges! Now we wrap up the code above and wrap it in a custom-called anonymous function (sometimes called a block-level scope or private scope), and that's not going to happen! Including the development of JS Plug-ins, is the same, we use a self-invoke anonymous function to write their own code wrapped up, it can! The package method is as follows:
Wrap it up with the top, and it's OK.
But there is another problem, when we look at Daniel's code, we often see ";" in order to avoid unnecessary errors such as code merging.
For example, we literally define a function:
var haoroomsblog=function () {
}
(function () {
}) ()
Because haoroomsblog this function is not followed by a semicolon, resulting in code error, in order to avoid this kind of situation, usually write this!
Wrapping your plugin code in the top is a simple plugin. (Note JS Plug-ins and jquery plug-ins are the same)
There's one more question.
Wrap your plugin in
It's almost perfect, you can say. But in order to allow you to develop a wider application of plug-ins, better compatibility, but also to consider the use of plug-ins some special practices, for example, some friends in order to avoid jquery and Zeptojs conflict, the jquery prefix "$" modified to "jquery", Some friends will modify the default document and other methods. In order for your plugin to work as usual in these things, then our approach is to wrap the code in the following:
;(function ($,window,document,undefined) {
//our code ...
}) (jquery,window,document);
Can avoid some of the above situation!
Excellent example
below, we have a basic level of plug-ins:
(function ($) {var privatefunction = function () {//code is run here} var methods = {Init:function (options) {return
This.each (function () {var $this = $ (this);
var settings = $this. Data (' Pluginname ');
if (typeof (settings) = = ' undefined ') {var defaults = {propertyname: ' Value ', Onsomeevent:function () {}}
Settings = $.extend ({}, defaults, options);
$this. Data (' Pluginname ', settings);
else {settings = $.extend ({}, settings, options);
}//code is running here});
Destroy:function (Options) {return $ (this). each (function () {var $this = $ (this);
$this. Removedata (' Pluginname ');
});
}, Val:function (options) {var somevalue = this.eq (0). html ();
return somevalue;
}
};
$.fn.pluginname = function () {var method = Arguments[0];
if (Methods[method]) {method = Methods[method];
arguments = Array.prototype.slice.call (arguments, 1);
else if (typeof (method) = = ' object ' | |!method) {method = Methods.init; } else {
$.error (' method ' + method + ' does not exist on Jquery.pluginname ');
return this;
Return to Method.apply (this, arguments);
}) (JQuery);
You may notice that the structure of the code I mentioned is quite different from the other plug-in code. Depending on your usage and requirements, the way plug-ins are developed may also be diversified. My goal is to clarify some of the concepts in the code, enough for you to find a way to understand and develop a jquery plugin.
Now, let's dissect our code!
Container: An instant execution function
Essentially, the code for each plug-in is included in an instant-executing function, as follows:
(Function (arg1, arg2) {
//Code
}) (Arg1, arg2);
An instant execution function, as its name suggests, is a function. What makes it unique is that it is contained within a pair of parentheses, which makes all the code run in the local scope of the anonymous function. This is not to say that the DOM (global variable) is masked within the function, but that the public variables and object namespaces inside the function cannot be accessed externally. This is a good start, so when you declare your variables and objects, you don't have to worry about conflicting variable names and existing code.
Now, because all of the public variables inside the function are inaccessible, it becomes a problem to use the jquery itself as an internal public variable. Just like normal functions, instant functions also pass in object arguments based on references. We can pass the jquery object into the function as follows:
(function ($) {
//local scope uses $ to refer to jquery
}) (jquery);
We passed in a function in which the public variable "JQuery" was passed into an instant execution, and we could refer to it by "$" in the function local (container). In other words, we call the container as a function, and the parameter of the function is jquery. Because we refer to "JQuery" as a public variable, rather than its abbreviated "$", so that we can be compatible with the prototype library. If you don't have to prototype or other libraries that use "$" as a shorthand, you won't have any impact, but knowing this usage is still a good thing.
Plugins: a function
A jQuery plugin is essentially a huge function that we cram into the jquery namespace, and of course we can easily use "jquery.pluginname=function" to achieve our goal, But if we do this, the code for our plug-in is in an unprotected state of exposure. "Jquery.fn" is shorthand for "jquery.prototype", meaning that when we get our plugin through the JQuery namespace, it's only writable (not modifiable). What can it actually do for you? It allows you to properly organize your own code and to understand how to protect your code from changes that are not required by the runtime. The best way to say this is that it's a good practice!
With a plugin, we get a basic jquery function:
(function ($) {
$.fn.pluginname = function (options) {
//code runs return here at here}
}) (JQuery);
The functions in the above code can be invoked like other jquery functions through "$ (' #element '). Pluginname ()". Notice how I added the "return this" statement, which was wrapped by a jquery object by returning a reference to a collection of original elements (contained in this) to produce the effect of a chained call. You should also note that "This" is a jquery object in this particular scope, equivalent to "$ (' #element ')."
Based on the returned object, we can sum up, in the above code, the use of "$ (' #element ')." The Effect of Pluginname () is the same as the effect of using the $ (' #element '). In the scope of your immediate execution function, it is not necessary to wrap this to a jquery object in the form of "$ (this)", because this is already a packaged jquery object.
Multiple elements: Understanding Sizzle
The selector engine used by jquery is called Sizzle,sizzle, which can provide a multivariate operation for your function (for example, the same element for all class names). This is one of the best features of jquery, but that's what you need to consider when developing plug-ins. Even if you are not prepared to provide multiple element support for your plugin, it is still a good practice to prepare for it.
Here I've added a little piece of code that lets your plug-in code function individually for each element in a multiple-element collection:
Function ($) {
//Add your plug-in code to the protected "FN" namespace in jquery, using "Pluginname" as the plug-in name
$.fn.pluginname = functions (options) {
//Return "This" (also the return value of each () of the function) to make a chained call. return
This.each (function () {
//here to run code, you can get each individual element
//For example: $ (this) by "this". Show ();
var $this = $ ( This);} ()})
(JQuery);
In the example code above, I didn't run the code on each element of my selector with each (). In the local scope of the function that is called by each (), you can use this to refer to each element that is handled individually, meaning that you can refer to its jquery object by using $ (this). In a local scope, I use the $this variable to store the jquery object, rather than using $ (this) every time the function is invoked, which is a good practice. Of course, it's not always necessary, but I've included it in my code. Also note that we will use each () for each individual method, so that we can return the value we need instead of a jquery object.
Here's an example, if our plugin supports a Val method, it can return the value we need:
$ (' #element '). Pluginname (' Val ');
will return the value we need instead of a jquery object
Features: Public and private methods
A basic function might work well in some cases, but a slightly more complex plug-in would need to provide a variety of methods and private functions. You might use different namespaces to provide a variety of ways for your plug-in, but it's best not to let your source code clutter up with unnecessary namespaces.
The following code defines a JSON object that stores a public method and shows how to use the main function in the plug-in to determine which methods are invoked and how to make the method work on each element of the selector.
(function ($) {//In our plug-in container, create a public variable to construct a private method var privatefunction = function () {//code here}//Create an object by literally, store We need a common method var methods = {//define each individual method in a literal object Init:function () {//For better flexibility, execute code R for each individual element from the main function and into each of the methods)
Eturn This.each (function () {//) creates a jquery object var $this = $ (this) for each individual element;
Execute code//For example: Privatefunction ();
});
Destroy:function () {///performs a method return This.each (function () {//Execute code}) for each element of the selector;
}
};
$.fn.pluginname = function () {//Get our methods, unfortunately, if we do this with function (method) {}, this will destroy everything var method = Arguments[0];
Verify if the method exists if (Methods[method]) {//If the method exists, save it for use//NOTE: I did this in order to wait for more convenient use of each () method = Methods[method]; If the method does not exist, verify that the object is an object (JSON object) or that method methods are not passed in} else if (typeof (method) = = ' object ' | |!method) {//If we pass in an object argument,
Or there is no parameter at all, the Init method is invoked to invoke methods = Methods.init; else {//If the method does not exist or the parameter is not passed in, an error is reported.
Methods that need to be invoked are not correctly called $.error (' method ' + methods + ' does not exist on Jquery.pluginname '); return this;
//Call our chosen method//Once again notice how we move each () from here to the return Method.call on each individual method (this);
}) (JQuery);
Notice that I take privatefunction as a global variable within a function. This practice can be accepted, considering that all code runs in the plug-in container, because it is only available in the scope of the plug-in. In the main function in the plug-in, I checked to see if the method that the incoming argument was pointing to exists. The Init method is run if the method does not exist or if the parameter is passed in as an object. Finally, if the incoming parameter is not an object but a nonexistent method, we will quote an error message.
Also be aware of how I use This.each () in every method. When we call Method.call (this) in the main function, this here is in fact a jquery object, which is passed into each method as this. So in the immediate scope of our approach, it's already a jquery object. It is only in the function called by each () that we need to wrap this in a jquery object.
Here are some examples of usage:
* Note that these examples can be run correctly in the current plug-in code, and not all plug-ins use the same Code structure///To execute the Init method $ ('. Cl ') for each element named ". ClassName" For each class.
Assname '). Pluginname ();
$ ('. ClassName '). Pluginname (' init '); $ ('. ClassName '). Pluginname (' init ', {}); Pass the "{}" object to the Init method as a function argument $ ('. ClassName '). Pluginname ({});
Executes the Destroy method $ ('. ClassName ') on an element of each class named ". ClassName" by passing the "{}" object to the Init method as a function parameter//. Pluginname (' destroy '); $ ('. ClassName '). Pluginname (' Destroy ', {}); Pass the Destroy method to the "{}" object as a function argument//All code can run normally $ ('. ClassName '). Pluginname (' init ', ' argument1 ', ' argument2 ');
Pass "Argument 1" and "Argument 2" to "init"//incorrect use of $ ('. ClassName '). Pluginname (' Nonexistantmethod ');
$ ('. ClassName '). Pluginname (' Nonexistantmethod ', {}); $ ('. ClassName '). Pluginname (' argument 1 '); Will attempt to invoke the "Argument 1" Method $ ('. ClassName '). Pluginname (' Argument 1 ', ' argument 2 '); Will attempt to invoke "Argument 1", "Argument 2" Method $ ('. ClassName '). Pluginname (' privatefunction '); ' Privatefunction ' is not a method
The
In the above example appears {} More than once, representing the parameters in the incoming method. In this section, the code above can function correctly, but the parameters are not passed into the method. Continue reading the next section and you will know how to pass parameters to a method. Settings Plugin: Incoming parameters many plug-ins support parameter passing, such as configuration parameters and callback functions. You can provide information for the method by passing in the JS key value to the object or function parameters. If your method supports more than one or two parameters, then there is no more appropriate way to pass in the object parameters.
(function ($) {var methods = {Init:function (options) {//Execute method return on each element)
. each (function () {var $this = $ (this); Create a default setting object var defaults = {propertyname: ' Value ', Onsomeevent:function () {}}///Using the Extend method from options and Def
The Aults object constructs a Settings object var settings = $.extend ({}, defaults, options);
Execute code});
}
};
$.fn.pluginname = function () {var method = Arguments[0];
if (Methods[method]) {method = Methods[method];
Our method is passed as a parameter and removed from the argument list because it is not required to invoke the method arguments = Array.prototype.slice.call (arguments, 1);
else if (typeof (method) = = ' object ' | |!method) {method = Methods.init;
else {$.error (' method ' + method + ' does not exist on Jquery.pluginname ');
return this;
//Use the Apply method to invoke our method and pass in the parameter return method.apply (this, arguments);
}) (JQuery);
As shown above, a "options" parameter is added to the method, and "arguments" is also added to the main function. If a method has been declared, the argument that calls that method is removed from the argument list before the parameter is passed in to the method. I used "apply ()" Instead of "call ()", "Apply ()" is essentially the same work as "call ()", but the difference is that it allows parameters to be passed in. This structure also allows for multiple parameters to be passed in, and if you are willing to do so, you can also modify the parameter list for your method, for example: "Init:function (Arg1, arg2) {}".
If you are using a JS object as a parameter, you may need to define a default object. Once the default object is declared, you can use "$.extend" to combine the values in the Parameter object and the default object to form a new Parameter object (in our case, "settings");
Here are some examples to illustrate the above logic:
var options = {
customparameter: ' Test 1 ',
PropertyName: ' Test 2 '
}
var defaults = {
propertyname: ' T EST 3 ',
onsomeevent: ' Test 4 '
}
var settings = $.extend ({}, defaults, options);
/*
Settings = = {
propertyname: ' Test 2 ',
onsomeevent: ' Test 4 ',
customparameter: ' Test 1 '
}< c15/>*/
Save Settings: Add persistent data
Sometimes you want to save settings and information in your plugin, and the "data" function in jquery can come in handy. It is very simple to use, it will try to get the data related to the element, if the data does not exist, it will create the appropriate data and add to the element. Once you use "data ()" To add information to the element, make sure you remember that when you no longer need the data, use "Removedata ()" To delete the corresponding data.
(function ($) {var privatefunction = function () {//Execute code} var methods = {Init:function (options) {//In each element
On the Execute method return This.each (function () {var $this = $ (this);
Try to get the settings, if they do not exist, return the "undefined" var settings = $this. Data (' Pluginname '); If get settings fails, it is created according to options and default if (typeof (settings) = = ' undefined ') {var defaults = {propertyname: ' VA
Lue ', Onsomeevent:function () {}} settings = $.extend ({}, defaults, options);
Save our newly created settings $this. Data (' Pluginname ', settings);
else {/If we get the settings, combine it with options (this is not necessary, you can choose not to do this) settings = $.extend ({}, settings, options);
If you want to save options each time, you can add the following code://$this. Data (' Pluginname ', settings);
}//execute code});
Destroy:function (options) {//Execute code return $ (this) in each element. each (function () {var $this = $ (this);
Executes code//delete elements corresponding to the data $this. Removedata (' Pluginname ');
}); Val:function (options) {//the code here passes. EQ (0) to get the first element in the selectorWe or get its HTML content as our return value var somevalue = this.eq (0). html ();
return value returns Somevalue;
}
};
$.fn.pluginname = function () {var method = Arguments[0];
if (Methods[method]) {method = Methods[method];
arguments = Array.prototype.slice.call (arguments, 1);
else if (typeof (method) = = ' object ' | |!method) {method = Methods.init;
else {$.error (' method ' + method + ' does not exist on Jquery.pluginname ');
return this;
Return to Method.apply (this, arguments);
}) (JQuery);
In the code above, I checked to see if the element's data exists. If the data does not exist, options and default are merged, built into a new setting, and then stored in the element with "data ()".