Create and enhance the dojo class
-- Translation from http://www.sitepen.com/blog/2010/07/01/creating-and-enhancing-dojo-classes/
Original author David Walsh
Like all the top-notch JavaScript toolkit, dojo is committed to making classes as flexible as possible, because it knows that different users may have completely different views on how a class and its methods work. Fortunately, Dojo provides a lot of methods for you to inherit or modify classes. Now let's look at some of these methods, which allow you to play with the dojo class as you like.
Create a dojo subclass
A typical method for creating a dojo class or subclass is to use dojo. Declare. Dojo. Declare registers the class to the namespace you specify and inherits any number of classes (passed by the second parameter ).
The following code describes how to create a subclass:
// Dojo. declare ('your. name. space ', superclass, {customproperties}); <br/> // or: <br/> // dojo. declare ('your. name. space', [superclass1, superclass2, superclass3], {customproperties}); <br/> dojo. provide ('davidhold. menu '); <br/> dojo. declare ('davynd. menu ', dijit. menu, {<br/>/* add your custom attributes and Methods */<br/> mycustomproperty: True, <br/> mycustommethod: function () {<br/>/* do some interesting things ...... */<Br/>}< br/> // all attributes and methods of dijit. Menu are automatically inherited <br/> });
The above Code creates a new class, which is "daven. menu is a new custom dojo class that inherits dijit. all methods and attributes of the menu class, and a new custom attribute and a custom method are added, which can be used to do anything. Now that we know how to create a subclass, let's write a practical Davy. Menu:
Dojo. provide ('davidhold. menu '); <br/> dojo. declare ('davynd. menu ', dijit. menu, {<br/> // a new option <br/> allowsubmenuhover: True, <br/> // another new option <br/> popupdelay: 500, <br/> // reload dijit. menu method <br/> onitemhover: function (item) {<br/> If (this. isactive | this. allowsubmenuhover) {<br/> This. focuschild (item); <br/> // use the new settings to trigger the menu <br/> If (this. focusedchild. popup & <br/>! This. focusedchild. Disabled & <br/>! This. hover_timer) {<br/> This. hover_timer = setTimeout (<br/> dojo. hitch (this, '_ openpopup'), <br/> This. popupdelay); <br/>}< br/> If (this. focusedchild) {<br/> This. focuschild (item); <br/>}< br/> This. _ hoveredchild = item; <br/>}< br/> });
The enhanced version of the dijit. Menu class. It has two new options and reloads the dijit. Menu method. The purpose is to provide a menu that opens a menu item when you hover over the mouse rather than click it.
You may be wondering how to call the method of the parent class in the subclass method? This is also simple:
//...... Some other methods <br/> somemethod: function () {<br/>/* do something you want to do here ...... */<Br/> // call the somemethod method of the parent class to reuse the original functions. <Br/> var result = This. inherited (arguments); <br/>/* Do something else here ...... */<Br/>}< br/> //...... Other methods
It can be seen that it is easy to create sub-classes. But what if you only need to modify an existing dojo class? The answer is patching!
Monkey Patching)
Sometimes inheriting an existing dojo class is not the best option (or even cannot be done at all ). You may be in such a situation that you can only patch existing dojo classes. At this time, monkey patching is the best choice. The so-called monkey patching is a process of modifying the prototype of an existing object (here it refers to the dojo class. This practice has the following advantages:
- All existing objects of this type are modified at the same time.
- You do not need to access the core dojo file.
- Since you have not modified the core file of dojo, it is relatively easy to upgrade the dojo version, because you do not need to track your previous changes.
- Your patches will also have better portability because they are not directly placed in the dojo core file.
The following code demonstrates the monkey patching mode:
(Function () {<br/> // Save the original prototype method <br/> var oldprototypesomemethod = <br/> dijit. somedijit. prototype. somemethod; <br/> // modify the prototype <br/> dijit. somedijit. prototype. somemethod = function () {<br/> /*...... Here are some new code ...... */<Br/> // only when you want to retain the original functions, call the original prototype method you just saved <br/> oldprototypesomemethod. call (this, arguments); <br/>}; <br/> })();
Now let's look at a practical example. I recently used the filteringselect control. I found that if the first option element in srcnode (that is, the Select element) does not have the value attribute (or the value is a Null String ), the label of this element is not displayed. This is a very strange bug and certainly not a behavior that meets your expectations. All I can do is patch the postmixinproperties method of the control class to fix this problem:
(Function () {<br/> var dffsp = dijit. form. filteringselect. prototype; <br/> // Save the original prototype method <br/> var oldpmip = dffsp. postmixinproperties; <br/> // modify the control prototype <br/> dffsp. postmixinproperties = function () {<br/> // If the select element currently has no value and its first option's value attribute is a null string, set the displayedvalue of the control to the initial label. <Br/> If (! This. store & this. srcnoderef. value = ") {<br/> var srcnoderef = This. srcnoderef, <br/> nodes = dojo. query ("> Option [value =''] ", srcnoderef); <br/> If (nodes. length) {<br/> This. displayedvalue = <br/> dojo. trim (nodes [0]. innerhtml); <br/>}< br/> // call the original method. We still need these original features. <Br/> oldpmip. Call (this, arguments); <br/>}; <br/> })();
This is just one of the good examples of using Monkey patching. Although patching may seem less elegant, it is indeed a necessary way to customize the dojo package in your hand.
Extended dojo class
The dojo. Extend method allows us to add new methods to the class prototype to provide these methods for all instances of the class. If a method passed to dojo. Extend already has a method with the same name in the class, it overwrites the original method.
The following example shows how to extend the dijit. Menu class so that the pop-up menu is displayed when you hover the mouse over the label, rather than when you click.
Dojo. extend (dijit. menu, {<br/> allowsubmenuhover: True, // a new setting option <br/> popupdelay: 500, // a new setting option <br/> onitemhover: function () {// reload the parent class method <br/> If (this. isactive | this. allowsubmenuhover) {<br/> This. focuschild (item); <br/> // use the new option to trigger the menu <br/> If (this. focusedchild. popup & <br/>! This. focusedchild. Disabled & <br/>! This. hover_timer) {<br/> This. hover_timer = setTimeout (Dojo. hitch (<br/> This, '_ openpopup'), this. popupdelay); <br/>}< br/> If (this. focusedchild) {<br/> This. focuschild (item); <br/>}< br/> This. _ hoveredchild = item; <br/>}< br/> });
Note that the original onitemhover method is not saved and used later, but the entire prototype is overwritten. Because we need to discard the original functions of this method. Now we have a dijit. Menu class that meets our needs, and the files in our dojo package are not disturbed.
Inherit, scale, or patch?
There is no hard rule about when to extend a class and when to apply patches. But I do have the following suggestions:
- Do not modify any dojo core files. If necessary, install patches or make extensions.
- If you need to access the original prototype object, use the patching method.
- To reuse code between multiple projects, use your custom namespace to create sub-classes.
- If portability is an important factor, use the extension class method.
Try to expand!
Extending the dojo class is the best way to fix bugs, enhance the built-in classes of dojo, and avoid repeated code. There are no restrictions in Dojo except those you impose on it!