📜 ⬆️ ⬇️

Writing a plugin for jQuery

This article is intended to give an idea of ​​the basic rules, the approaches that give the best results, and common mistakes that you should pay attention to when developing plug-ins for jQuery.


Getting started


First we create a new property-function for the jQuery object, where the name of our property will be the name of our plugin:

jQuery.fn.myPlugin = function() { //      }; 

But wait, where is the dollar badge we are used to, which we all know well? It is still here, and so that it does not conflict with other libraries that can also use the dollar symbol, it is recommended to “wrap” the jQuery object into a directly executed expression function (IIFE, Immediately Invoked Function Expression) that links the jQuery object with the “$ "so that it is not overridden by another library at run time.
')
 (function( $ ) { $.fn.myPlugin = function() { //      }; })(jQuery); 

That's better. Now inside this closure, we can use the dollar sign as we please.

Context


Now we have a shell inside which we can start writing the plug-in code. But before we begin, I would like to say a few words about the context. In the immediate scope of the function of our plugin, the keyword “this” refers to the jQuery object for which this plugin was invoked.

And here they often make mistakes, assuming that in other calls, where jQuery accepts a callback function, “this” points to the element of the DOM tree. That, in turn, leads to the fact that the developers additionally wrap “this” in the jQuery function.

 (function( $ ){ $.fn.myPlugin = function() { //    $(this),   "this" -    jQuery //  $(this)   $($('#element')); this.fadeIn('normal', function(){ //  "this" -    DOM }); }; })( jQuery ); 

  $('#element').myPlugin(); 

The basics


Now that we understand how to work with the context, we will write a jQuery plugin that performs useful work.

 (function( $ ){ $.fn.maxHeight = function() { var max = 0; this.each(function() { max = Math.max( max, $(this).height() ); }); return max; }; })( jQuery ); 


 var tallest = $('div').maxHeight(); //     div- 

This is a simple plugin that, using .height () , returns the height of the highest div on the page.

We support the possibility of call chains


The previous example calculates and returns the integer value of the highest div on the page. Typically, a plugin modifies a set of DOM tree elements, and passes them on to the next method in the call chain. This is the beauty of jQuery and one of the reasons for its popularity. So in order for your plugin to support call chains, make sure your plugin returns this.

 (function( $ ){ $.fn.lockDimensions = function( type ) { return this.each(function() { var $this = $(this); if ( !type || type == 'width' ) { $this.width( $this.width() ); } if ( !type || type == 'height' ) { $this.height( $this.height() ); } }); }; })( jQuery ); 

 $('div').lockDimensions('width').css('color', 'red'); 

Since the plugin returns this in its immediate scope, it therefore supports call chains, and the jQuery collection can continue to be handled by jQuery methods, such as .css , for example.
And, if your plugin should not return any calculated value, you should always return this in the immediate scope of the plugin function. Arguments that are passed to the plugin when called are passed to the immediate scope of the plugin function. So, in the previous example, the string 'width' is the value of the “type” parameter for the plugin function.

Settings and defaults


For more complex and customizable plugins, providing a large number of customization options, it is better to have default settings that expand (using $ .extend ) during a plugin call.

So instead of calling a plugin with a large number of parameters, you can call it with one parameter, which is the object literal of the settings you want to expand. For example, you can do this:

 (function( $ ){ $.fn.tooltip = function( options ) { //   -,     ,    var settings = $.extend( { 'location' : 'top', 'background-color' : 'blue' }, options); return this.each(function() { //     tooltip }); }; })( jQuery ); 

 $('div').tooltip({ 'location' : 'left' }); 

In this example, after calling the tooltip plug-in with the specified parameters, the value of the location parameter ('location')
is overridden by the value of 'left', while the value of the 'background-color' parameter remains equal to 'blue'. As a result, the settings object contains the following values:

 { 'location' : 'left', 'background-color' : 'blue' } 

This is a good way to create customizable plugins without having to define each of the available settings.

Namespace Definition


Correct definition of the namespace for a plugin is very important and provides a fairly low probability of overriding by another plugin or code running on the same page. In addition, the definition of the namespace simplifies development, as it simplifies tracking the necessary methods, events and data.

Plug-in methods

Under any circumstances, one plugin must define no more than one namespace for the jQuery.fn object.

 (function( $ ){ $.fn.tooltip = function( options ) { //   }; $.fn.tooltipShow = function( ) { //  }; $.fn.tooltipHide = function( ) { //  }; $.fn.tooltipUpdate = function( content ) { // !!! }; })( jQuery ); 

This practice is not welcome, as it pollutes the $ .fn namespace
To avoid this, combine all the methods of your plugin into one object literal and call them, passing the name of the method as a string.

 (function( $ ){ var methods = { init : function( options ) { //    }, show : function( ) { //  }, hide : function( ) { //  }, update : function( content ) { // !!! } }; $.fn.tooltip = function( method ) { //    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 + '    jQuery.tooltip' ); } }; })( jQuery ); //   init $('div').tooltip(); //   init $('div').tooltip({ foo : 'bar' }); 

 //   hide $('div').tooltip('hide'); 

 //   update $('div').tooltip('update', '   '); 

This type of plug-in architecture allows you to encapsulate all of your methods in the parent of the plug-in closure, and call them, first passing the name of the method as a string, and then passing any additional parameters for this method. This approach to encapsulating methods is a standard in the jQuery plugin community and is used in countless plug-ins and widgets in jQueryUI.

Developments

A little-known feature of the bind method is that it allows you to define namespaces for related events. If your plugin binds some functionality to an event, then the namespace for this event will be a good tone. And if you later need to decouple this functionality from the event, then you can do it without affecting the functionality that can be attached to this same type of event.

You can define a namespace for your events by simply adding a period and name of the namespace to the name of the type of event you are associating with.

 (function( $ ){ var methods = { init : function( options ) { return this.each(function(){ $(window).bind('resize.tooltip', methods.reposition); }); }, destroy : function( ) { return this.each(function(){ $(window).unbind('.tooltip'); }) }, reposition : function( ) { // ... }, show : function( ) { // ... }, hide : function( ) { // ... }, update : function( content ) { // ... } }; $.fn.tooltip = function( method ) { 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 + '    jQuery.tooltip' ); } }; })( jQuery ); 

 $('#fun').tooltip(); //   ... $('#fun').tooltip('destroy'); 

In this example, when the tooltip plugin was initialized using the init method, it associates the reposition method with the window resize (resizing) event, specifying the name tooltip namespace. Later, when the developer intends to destroy the tooltip object, he can untie all the handlers attached to the plugin by specifying the appropriate namespace. In this case, the 'tooltip' for the unbind method. This allows you to safely unlink handlers from events without the risk of accidentally unlink an event associated with a handler outside this plugin.

Data

Often, during plug-in development, you may encounter the need to save states or check whether the plug-in has already been initialized for the specified element. Using the data method from jQuery is a good way to track the state of variables for each element. However, instead of tracking a lot of separate data calls with different names, it is recommended to use one object literal that will combine all your variables under the same roof and you will access this object through one namespace.

 (function( $ ){ var methods = { init : function( options ) { return this.each(function(){ var $this = $(this), data = $this.data('tooltip'), tooltip = $('<div />', { text : $this.attr('title') }); //      if ( ! data ) { /* *    */ $(this).data('tooltip', { target : $this, tooltip : tooltip }); } }); }, destroy : function( ) { return this.each(function(){ var $this = $(this), data = $this.data('tooltip'); //   !!11 $(window).unbind('.tooltip'); data.tooltip.remove(); $this.removeData('tooltip'); }) }, reposition : function( ) { // ... }, show : function( ) { // ... }, hide : function( ) { // ... }, update : function( content ) { // ...} }; $.fn.tooltip = function( method ) { 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 + '    jQuery.tooltip' ); } }; })( jQuery ); 

Using data allows you to track the state of variables between calls to your plugin. Defining a namespace for data in a single object literal provides both simple centralized access to the properties of the plug-in and reduces the name space of data, which allows you to simply delete unnecessary data as needed.

Conclusion and useful tips


Creating jQuery plugins allows you to get the most out of this library and abstract your most successful solutions and frequently used functions into reusable code that can save you time and make the development process more efficient. Below is a brief excerpt of what should be remembered while developing your jQuery plugin:

Source: https://habr.com/ru/post/158235/


All Articles