📜 ⬆️ ⬇️

Implementing the ElementTraversal Interface

Quite a lot of browsers (Opera 9.6, Google Chrome 2, Safari 4, Firefox 3.5) have got support for the very convenient ElementTraversal interface, which allows you to navigate the DOM tree, ignoring text nodes. In these browsers, the following set of new getters is available for each element:Without going into details of the implementation of these getters and relying on the words from the specification:
The ElementTraversal interface is a set of read-only attributes ...
we will call them further attributes.

Let's clarify: the elements are called DOM-tree nodes that have the nodeType property equal to 1; elements correspond tags.

The use of these attributes should improve the performance of JavaScript applications when navigating the DOM tree, since there is no need to check nodeType nodes in the loop and use additional wrapper functions. And the childElementCount attribute lets you know if the current node has children at all, unlike the almost useless hasChildNodes method. Of course, you can check for the presence of child elements as follows:
node.getElementsByTagName( "*" ).length
But this method is too wasteful; the childElementCount built-in attribute should theoretically work much faster.
')
All this is certainly good and interesting, but what to do with old browsers that do not support the ElementTraversal interface? Obviously, you have to write additional functions for each attribute. You can see their implementation in the article “ Quick search for DOM elements ”, although I think that for many it will not be difficult to write such functions yourself, there is nothing difficult about that.

And now the most interesting thing is that Internet Explorer 8 has the opportunity to create these same getters and setters . It is strange only why in any review on innovations IE8 did not sound about this powerful and useful mechanism. In JScript, you can now create getter or setter using the defineProperty method of the built-in Object. We recall that this possibility, through the methods __defineGetter__ and __defineSetter__, was originally in browsers based on Gecko, as it turned out already in Safari 3, and in Opera 9.6 implemented this mechanism.

So, having the ability to create getters, we can implement support for the ElementTraversal interface in Internet Explorer 8, Mozilla Firefox 2+ and Safari 3+, but Opera 9.6 already supports it.

It remains to write the code:
// <br> var element = document .createElement( "div" );<br><br> // , ElementTraversal <br> if ( typeof element.firstElementChild == "undefined" ) {<br><br> // <br> var ElementTravrsal = {<br><br> // <br> firstElementChild: function () {<br> // <br> var node = this .firstChild;<br> // <br> // null <br> while (node && node.nodeType != 1) node = node.nextSibling;<br> // null <br> return node;<br> },<br><br> // <br> lastElementChild: function () {<br> // <br> var node = this .lastChild;<br> // <br> // null <br> while (node && node.nodeType != 1) node = node.previousSibling;<br> // null <br> return node;<br> },<br><br> // <br> nextElementSibling: function () {<br> // <br> // <br> var node = this ;<br> // <br> // null <br> do node = node.nextSibling<br> while (node && node.nodeType != 1);<br> // null <br> return node;<br> },<br><br> // <br> previousElementSibling: function () {<br> // <br> // <br> var node = this ;<br> // <br> // null <br> do node = node.previousSibling;<br> while (node && node.nodeType != 1);<br> // null <br> return node;<br> },<br><br> // <br> // , children <br> childElementCount: typeof element.children == "undefined" ? function () {<br> // children, <br> // <br> var list = this .childNodes,<br> // <br> i = list.length,<br> // <br> j = 0;<br> // , <br> while (i--)<br> // , <br> if (list[i].nodeType == 1)<br> // <br> j++;<br> // 0 <br> return j;<br> } : function () {<br> // children, <br> // <br> // <br> return this .children.length;<br> }<br> };<br><br> // IE8 <br> if (Object.defineProperty)<br> for ( var property in ElementTravrsal)<br> if (ElementTravrsal.hasOwnProperty(property))<br> Object.defineProperty(Element.prototype, property, {<br> get: ElementTravrsal[property]<br> });<br><br> // Firefox 2+ Safari 3+ <br> if (Object.__defineGetter__)<br> for ( var property in ElementTravrsal)<br> if (ElementTravrsal.hasOwnProperty(property))<br> HTMLElement.prototype.__defineGetter__(property, ElementTravrsal[property]);<br><br>}
By including this code in the project, you can now use ElementTraversal in most browsers:For the development of some services or administrative interfaces of this list may well be enough. Well, if you need support for all browsers, without additional features, as in the article below the link above, you can not do. Or you can still expand the list of supported browsers? If you have ideas on how to do this in other browsers, write in the comments, even if they are irrational decisions, the implementation itself is interesting.

The attributes of the new interface are used in the same way as the old firstChild, lastChild, nextSibling, and so on. For example, take the following XHTML code:
< div id ="test" > <br> TextNode<br> < div > TextNode </ div > <br> TextNode<br> < p > TextNode </ p > <br> TextNode<br> </ div > <br>TextNode<br> < p > TextNode </ p >
And let's do a few moves through the DOM tree in JavaScript:
// <br> // "test" <br> var node = document .getElementById( "test" );<br><br> // tagName <br>alert(node.nextElementSibling.tagName); // → "P" <br><br> // <br>node = node.lastElementChild;<br><br> // , ? <br>alert(node.childElementCount); // → "0" <br><br> // ? <br>alert(node.hasChildNodes()); // → "true"
If it was interesting, I can write more about using getters and setters in JScript and JavaScript in the next article.

Archive with the code from the article: ElementTraversal.zip

Update: transferred to the thematic blog, thanks for the karma :-)

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


All Articles