This is a continuation of my article
"Client Optimization and Development Stages .
" It gave recommendations on how to create fast sites, and including, in fact, I told what a web developer should do in order to follow the principles of “Unobtrusive JavaScript”:
- separation of structure (HTML) / design (CSS) and behavior (JavaScript);
- using JavaScript to improve the usability of an already working application;
- use of Graceful degradation technique - if the browser does not support certain functions that we add to the application using JavaScript, the application still remains working.
In the same article I would like to talk about the algorithm for implementing the principles of "unobtrusiveness" in JavaScript.
JavaScript functionality is a derivative of HTML and CSS.
It is relatively easy to create a page and implement some server functionality. Difficult - to build a foundation for the work of JS-programmers. Semantic layout, in which each structural HTML element is selected based on its purpose, is a necessary, but not sufficient, basis for such a foundation.
Functional design
Effective information exchange within the team is a guarantee of high speed and quality of development. The semantic layout does not impose on the HTML maker-up the requirement to show the JS programmer the rules for displaying the page in dynamics. This is the task of functional design, a special set of CSS rules that show how the page should change after any user action. I will give an example:
< style type = " text / css " >
.contents li {display: block; }
.v1 .contents li.v1, .v2 .contents li.v2, .v3 .contents li.v3 {display: none; }
.links li {display: none; }
.v1 .links li.v1, .v2 .links li.v2, .v3 .links li.v3 {display: block; }
</ style >
< div class = " v1 v2 " >
< ol class = " contents " >
< li class = " v1 " > content1 </ li >
< li class = " v2 " > content2 </ li >
< li class = " v3 " > content3 </ li >
</ ol >
< ol class = " links " >
< li class = " v1 " > link1 </ li >
< li class = " v2 " > link2 </ li >
< li class = " v3 " > link3 </ li >
</ ol >
</ div >
The screen will display 3 lines:
content3 ,
link1 and
link2 . Here, the CSS rules are written in such a way that when adding / removing the root DIV-
v1 ,
v2 or
v3 in the class, the LI elements of the
.contents and
.links lists will
hide or
appear . These CSS rules will be the “instruction” for the JS programmer - now he can easily make any function of
SwitchContentsAndLinks that would “switch” the visibility of the contents of the DIV.
Thus, the
semantic layout and
functionality of the design are the links between the structure, design and behavior of the document and a solid foundation for the development of JavaScript functionality.
')
Components - unobtrusive JavaScript software modules
A component is a JavaScript object associated with a DOM element. For simplicity, we can say that the Component and the DOM element are the same.
Components can:
- contain functions of event handlers of the DOM element;
- change the state of your DOM element;
- contain child components, be a child component;
- share information with other components.
In the HTML code above, there are 7 components:
- 1) DIV - can change its className by some signal;
- 2-7) LI - can send a signal to its parent component by clicking on itself.
Creating Objects-Component
The “The Exceptional Performance” team from Yahoo
developed a set of rules for creating fast Web pages . The list includes 34 items, combined into 7 categories. The principles of Unobtrusive JavaScript do not conflict with these rules, on the contrary - their goals are similar. Therefore, some points of the
Algorithm will be supported by references to these rules:
- In order to determine which of the DOM elements are Components, it is necessary to mark them somehow. And also describe what files you need to download for each of them. When developing our project, we decided to make a “mark” inside the className of the DOM element: it is built from three parts separated by a space:
- The first part: “js” is a sign that the DOMElement is a component;
- The second part: the class name of the component. By class name, you can unambiguously determine where it lies on the server;
- The third part, optional - is Presentation (design) in its pure form.
- If the component needs additional data, then we pass it in the attributes of the DOM element;
- If a component requires a certain array of data, then this data can be transferred to the onclick of the DOM element: onclick = "return {data: {...}}"; during initialization, you can read the data using the construction of the form data: var data = DOMElement.onclick ();
- In order not to interfere with the loading of content and images , we place the download code of the main JS library before closing the body tag;
- After the page loads , we select the elements with the CSS selector : (1) look for all elements that have the js class; (2) from the string value of the className of the DOM element we take the name of the component class (ideally, this is the first and last time when we search for elements in the document).
- Having a list of component classes of the page, we need to load the missing functionality. There can be quite a few different classes of components on the page, so for loading we use the method described in my last article (in short: for the classes of components aaa_bbb and ccc_ddd , that is, for the files /jas/aaa/bbb.js and / jas / ccc /ddd.js only one request is formed to the server of the form /jas/aaa,bbb.js;ccc,ddd.js/ )
- After loading all the necessary functionality, we can create instance objects of the Component classes.
Classes Component
Speaking "class" I mean
Class in the understanding of the classic OOP. The use of this approach was dictated by the need to reuse the code: by calling the constructors and destructors of the parent classes after the object is created and before it is destroyed. I have laid out a description of how inheritance occurs in my “classes” in my article-application
“Classes in JavaScript: calling methods of the parent class” .
Returning to the Components, I would like to show the class hierarchy currently available:
JooS.Class
|
+ - JooS.TextElement
|
+ - JooS.Element
|
+ - Beatle.Class
|
+ - Any Final Component Class
JooS.Class - Abstract class, common ancestor.
JooS.Element - The “DOM-element” class, contains the htmlElement property and methods for working with it.
Beatle.Class - Abstract class "Component", contains methods for working together components
Also, especially for this article, I prepared a page with ready-made components:
http://beatle.joos.nnov.ru/ . The page consists of three parts:
- List - contains components for HTML code, given in the chapter “Functional appearance”. 3 component classes are used;
- "Animated" PNG - class 1 is used
- Comment form - 7 classes are used.
- + 1 more class GoogleAnalytics for body to count all (based on the article Overclock counters: from myths to reality )
The principles of joint work of several components will be described below using the example of the “Comment Form”.
Exchange of information between components
Collaboration Component implies “information sharing”. The way in which the components knowing each other, directly call the functions of the neighboring components is not suitable, because this contradicts the third principle of Unobtrusive JavaScript - the neighboring component may simply not be on the page and a call like
this.neibourComponent.method1 () will cause a JS error. Checks for the existence of neighbors for such a case are also not suitable - there can be a lot of such checks + it is not known in advance how many components will want to know this information.
On the other hand, the need to exchange information occurs inside the component only when the state of the component changes, for example, after clicking on its DOM element. Let's call this state change
“Event Component” (hereinafter - simply “Event”). Such Events are characterized by an identifier (name), input parameters and the function of processing input parameters (for example, to convert the string "10px" to the number 10).
Let's call the component that generates the event,
"Throwing" , and the component that subscribed to this event, -
"Listener" . Let
's call the
“Manager” component, through which the “Throwing” sends the event to the “Listeners”. In order to transmit an event, “Throwing” and “Listener” must first register with the “dispatcher-parent component” and only after that start the transfer. Such registration occurs in the component constructor.
It turned out that any component can play the role of "Throwing", "Listener" and "Dispatcher" at the same time. This caused long disputes in our team, but in the end, everyone agreed that the structure of the HTML code not only allows, but also dictates this solution.
Almost always, the “Listener” expects an event from its neighboring component, and not from another such, but located at the other end of the page: for example, the Form
validator component can wait for the “form filled” event only from its FORM component, and -FORM expects value change events only from its child components INPUTs. Thus, there is a need for several event dispatchers + for the system to work without failures there must be at least one dispatcher “by default”.
A side effect of such a system was the ability to “throw an event at itself” or “listen to an event at home” and the need to register with a “parent-component-clearly defined Class” or a “strictly parent-component”.
Except for the case when the initiator of the event is the “source of information”, there is an option when the “consumer of information” can act as the initiator. This is solved in the same way through the event mechanism:
- The event "Listener" function throws Exception ( throw {/ * object_withInformation * /} }}
- object_information will be delivered as a result of the function to throw Event Components ('name', parameters);
Example: the FORM component throws a form-filled event to the validator; in case of an error, the validator returns an error-description-object.
Conclusion
Here is such an algorithm. It may seem seemingly difficult for you, but in fact, having such tools at your fingertips, you can quickly create quite complex things. This is one of the rare cases where seemingly artificial constraints and complexities (“semantic layout” and “functional design”) give a big boost in the team’s performance and the result of its work.
They say that JavaScript slows down the Web ... I wanted to show this and the
previous article that everything is in our hands: we can make the Web faster! (well, or at least, create visibility =)
Thanks for attention.