Link: http://learn.jquery.com/jquery-ui/widget-factory/how-to-use-the-widget-factory/
At the beginning, we will create a progress bar plug-in that can only be set once. As we can see below, you can call jquery. widget to complete the operation. It has two parameters: one is the plug-in name, and the other is that the object literally contains the function for creating the plug-in. When our plug-in is called, it creates a plug-in instance and all functions are executed in the context of the instance. This is different from the standard jquery plug-in. Context is an object rather than a DOM element. context is always a single object and never a set.
$.widget( "custom.progressbar", { _create: function() { var progress = this.options.value + "%"; this.element .addClass( "progressbar" ) .text( progress ); }});
The plug-in name must contain a namespace. In this case, we use the custom namespace. What is restricted in the current namespace is that we must use a namespace. We can also see that the widget factory provides us with two properties. This. element is a jquery object that contains only one dom element. If our plug-in is called on a jquery object that contains multiple elements, a plug-in instance is created for each element and each instance has its own this. element. The second property is this. options, which is a hash containing key/value pairs for the configuration of all our plug-ins. You can configure the plug-in as follows.
$( "<div></div>" ) .appendTo( "body" ) .progressbar({ value: 20 });
When we call jquery. widget, a function will be added to jquery. FN to expand jquery (this is the method for creating standard plug-ins ). The name of the added function depends on the name of the jquery. widget you input. The name does not contain the namespace. In this case, it should be "progressbar ". As in the following example, we can set any default configuration items. When designing an API, you should consider most of the use cases of the plug-in, so that you can set most of the default values and make all the configurations optional.
$.widget( "custom.progressbar", { // Default options. options: { value: 0 }, _create: function() { var progress = this.options.value + "%"; this.element .addClass( "progressbar" ) .text( progress ); }});
Calling plugin Methods
Now we can initialize our progress bar. We will call the method on the plug-in instance to add the plug-in function. To define a plug-in method, you only need to include the corresponding function in the object literal parameters that pass in jquery. widget. You can also add a slide line to the function name to define a private function. (The word "function" uses "method" here will be more accurate)
$.widget( "custom.progressbar", { options: { value: 0 }, _create: function() { var progress = this.options.value + "%"; this.element .addClass( "progressbar" ) .text( progress ); }, // Create a public method. value: function( value ) { // No value passed, act as a getter. if ( value === undefined ) { return this.options.value; } // Value passed, act as a setter. this.options.value = this._constrain( value ); var progress = this.options.value + "%"; this.element.text( progress ); }, // Create a private method. _constrain: function( value ) { if ( value > 100 ) { value = 100; } if ( value < 0 ) { value = 0; } return value; }});
To call a method on a plug-in instance, you need to pass the method name to the jquery plug-in. If you call a method that requires parameters, you only need to input parameters after the passed method name.
Note: An exception may occur when executing the method by adding the method name to the jquery function. This is done to prevent the jquery namespace from being contaminated when the chain call capability is maintained. Later in this article, we will introduce a more natural method.
var bar = $( "<div></div>" ) .appendTo( "body" ) .progressbar({ value: 20 }); // Get the current value.alert( bar.progressbar( "value" ) ); // Update the value.bar.progressbar( "value", 50 ); // Get the current value again.alert( bar.progressbar( "value" ) );
Working with options
In our plug-in, option is one of the methods that can be used automatically. The option method allows you to obtain or set configuration items after initialization. This effect is like the. CSS () and. ATTR () is the same: You can pass only one name as getter, or pass one name and one value as a single setter, you can even pass a hash table (Object literal) that contains multiple name-value pairs to set multiple values in sequence. When it is used as a getter, the plug-in returns the value of the current pair name of option. When it is used as a setter, the plug-in calls the _ setoption method in the plug-in for each name and value. You can override the _ setoption method in the plug-in to change the corresponding configuration item. To Independently respond to the situation where multiple attributes change at the same time, we can rewrite _ setoptions.
$.widget( "custom.progressbar", { options: { value: 0 }, _create: function() { this.element.addClass( "progressbar" ); this.refresh(); }, _setOption: function( key, value ) { if ( key === "value" ) { value = this._constrain( value ); } this._super( key, value ); }, _setOptions: function( options ) { this._super( options ); this.refresh(); }, refresh: function() { var progress = this.options.value + "%"; this.element.text( progress ); }, _constrain: function( value ) { if ( value > 100 ) { value = 100; } if ( value < 0 ) { value = 0; } return value; }});
Adding callbacks
One of the simplest ways to make your plug-in scalable is to add a callback function so that you can respond when the status of the plug-in changes. Next, let's take a look at how to add a callback function to display a prompt when the progress bar reaches 100%. The _ trgger method requires three parameters: the callback function name, the event object of the initialization callback function, and the event-related name-value pair data. Only the function name is required, but other parameters are very useful for users who want to implement more personalized features on your plug-in. For example, if we create a drag-and-drop plug-in, when the drag-and-drop callback function is triggered, we can pass in the mouse's moving event object. In this way, the user can respond to the drag through the coordinate value provided by the event object. Note that the originally passed _ trigger must be a jquery event object, rather than a local browser event object.
$.widget( "custom.progressbar", { options: { value: 0 }, _create: function() { this.element.addClass( "progressbar" ); this.refresh(); }, _setOption: function( key, value ) { if ( key === "value" ) { value = this._constrain( value ); } this._super( key, value ); }, _setOptions: function( options ) { this._super( options ); this.refresh(); }, refresh: function() { var progress = this.options.value + "%"; this.element.text( progress ); if ( this.options.value == 100 ) { this._trigger( "complete", null, { value: 100 } ); } }, _constrain: function( value ) { if ( value > 100 ) { value = 100; } if ( value < 0 ) { value = 0; } return value; }});
Callback functions are only optional in nature, so you can configure the callback function just like other items. No matter when the callback function is executed, a related event is triggered at the same time. The event type is determined by the plug-in name and the callback function name. Both callback and event require two parameters: An event object and a series of name-value pairs related to the event, as shown below. Your plug-in may want to disable some features. The best way is to cancel the callback function. You can cancel a callback function or related events, just as you can call event. preventdefault () or return false to cancel any local events. If you cancel the callback function, the _ trrgger method returns false, and you can implement the corresponding function in the plug-in.
var bar = $( "<div></div>" ) .appendTo( "body" ) .progressbar({ complete: function( event, data ) { alert( "Callbacks are great!" ); } }) .bind( "progressbarcomplete", function( event, data ) { alert( "Events bubble and support many handlers for extreme flexibility." ); alert( "The progress bar value is " + data.value ); }); bar.progressbar( "option", "value", 100 );
Looking under the hood
Now we know how to create a plug-in through the widget factory. Let's take a look at how it works. When you call jquery. widget, it creates a constructor for your plug-in and sets the input object literal to the prototype of all your plug-in instances. All functions automatically added to your plug-in come from the prototype of a basic plug-in, which is defined in jquery. widget. prototy. When a plug-in instance is created, the prototype is stored in an original Dom element through jquery. Data, And the plug-in name serves as the key. (The following two sentences are not quite clear. I suggest reading the original article)
Because the plug-in instance is directly associated with the DOM element, you can directly obtain the plug-in instance if you like, instead of using the exposed plug-in method. This allows you to directly call a method on the plug-in instance instead of passing the method name in the form of a string. In this way, you can also directly access the attributes of the plug-in.
var bar = $( "<div></div>" ) .appendTo( "body" ) .progressbar() .data( "progressbar" ); // Call a method directly on the plugin instance.bar.option( "value", 50 ); // Access properties on the plugin instance.alert( bar.options.value );
You can also directly call the constructor and pass the configuration items and DOM elements as parameters to create a plug-in instance, so that you do not need to use the plug-in method.
var bar = $.custom.progressbar( {}, $( "<div></div>" ).appendTo( "body") ); // Same result as before.alert( bar.options.value );
Extending a plugin's prototype
One of the biggest advantages of making the plug-in have constructor and prototype is that it is easy to expand. By adding or modifying the method to the plug-in prototype, we can modify the behavior of all the instances of the plug-in. For example, if we want to add a zero-setting method to my progress bar plug-in, we can add it to the prototype and directly call it on all instances.
$.custom.progressbar.prototype.reset = function() { this._setOption( "value", 0 );};
Cleaning up
In some cases, we want to allow users to apply and cancel our plug-ins at any time. You can use the _ destroy method. Inside _ destroy, you should undo all initialization tasks or things that will be used later. The _ destroy method is called in the destroy method. The destroy method is automatically called when the elements bound to your plug-in are removed from the Dom. This can also be used for garbage collection. Base class. the Destry () method also implements some general cleanup work, such as removing the associated instance from the widget Dom element and removing the events bound to the widget namespace, contact all events bound through _ Bing.
$.widget( "custom.progressbar", { options: { value: 0 }, _create: function() { this.element.addClass( "progressbar" ); this.refresh(); }, _setOption: function( key, value ) { if ( key === "value" ) { value = this._constrain( value ); } this._super( key, value ); }, _setOptions: function( options ) { this._super( options ); this.refresh(); }, refresh: function() { var progress = this.options.value + "%"; this.element.text( progress ); if ( this.options.value == 100 ) { this._trigger( "complete", null, { value: 100 } ); } }, _constrain: function( value ) { if ( value > 100 ) { value = 100; } if ( value < 0 ) { value = 0; } return value; }, _destroy: function() { this.element .removeClass( "progressbar" ) .text( "" ); }});
Closing comments
Widget factory is only one way to create a stateful plug-in. Other models have their own advantages and disadvantages. Widget factory solves many common problems for you, this greatly improves productivity and code reusability. Just like many other stateful plug-ins, your plug-ins are closer to jquery UI.
You may have noticed that we may feel like using the custom name in this article. The UI namespace has been occupied by the official jquery UI. When creating your plug-in, you should use your own namespace. This will make the plug-in more clear about its source and whether it belongs to a larger plug-in group.