Traversing the DOM is, perhaps, the single most common task a JavaScript front-end developer must face. But the task is not always as easy as it might seem, especially if, for any number of reasons, you don't want to use an existing JavaScript library or adding a number of class names and ID values doesn't make sense.
As an example, how do you select a specific child node from the array of possible children? One solution is to use a for loop that checks to see if the particular child node in view is the node you want to act on.
For example, below is some basic HTML that might be used to create a fly-out or mega menu navigation. The markup includes a top level unordered list with two list items. Each list item contains a div element that in turn has a nested unordered list with several items.
<!doctype html> <html lang="en"> <head> <title>childNode Example</title> <link type="text/css" rel="stylesheet" href="style.css"> <link rel="icon" type="image/png" href="favicon.png"> </head> <body> <div id="wrapper"> <div> <ul class="level1-ul"> <li class="level1-li"><a href="#">Product 1</a> <div class="level2-div"> <ul class="level2-ul"> <li class="level2-li"><a href="#">Sub 1</a></li> <li class="level2-li"><a href="#">Sub 2</a></li> <li class="level2-li"><a href="#">Sub 3</a></li> <li class="level2-li"><a href="#">Sub 4</a></li> <li class="level2-li"><a href="#">Sub 5</a></li> <li class="level2-li"><a href="#">Sub 6</a></li> </ul><!--end level2-ul--> </div><!--end level2-div--> </li><!--end level1-li--> </ul><!--end level1-ul--> <ul class="level1-ul"> <li class="level1-li"><a href="#">Product 2</a> <div class="level2-div"> <ul class="level2-ul"> <li class="level2-li"><a href="#">Sub 1</a></li> <li class="level2-li"><a href="#">Sub 2</a></li> <li class="level2-li"><a href="#">Sub 3</a></li> <li class="level2-li"><a href="#">Sub 4</a></li> <li class="level2-li"><a href="#">Sub 5</a></li> <li class="level2-li"><a href="#">Sub 6</a></li> </ul><!--end level2-ul--> </div><!--end level2-div--> </li><!--end level1-li--> </ul><!--end level1-ul--> </div> </div><!--end wrapper--> <script src="js3.js"></script> </body> </html>
If I wanted to act on the div element nested beneath the top-level list items, I could loop through all of the children stopping when I had gotten to the proper child node. Here is a bit of CSS that lays out the HTML included above. Notice that there is a style for "level1-div" and for "show" that describes the visibility of an element.
body {margin: 0; padding: 0; background: #FFF; font-family: Segoe UI; color: #505050; }
img {border: none;}
h1 {color: #3F70BC;}
#wrapper {margin: 50px auto; width: 800px;}
#header {margin:0; padding0;}
/*LEVEL1*/
.level1-ul {list-style: none; margin: 0; padding: 0;}
.level1-li {position: relative; float: left; background: pink; display: block; padding: 5px}
.level1-li a {background: white;}
/*LEVEL2*/
.level2-div {position: absolute; visibility: hidden;}
.level2-ul {list-style: none; margin: 0; padding: 0;}
.show {visibility: normal;}
Using a for loop, I will cycle through a given top level list item, stopping when I hit the desired node, which in this case is a div. The function containing this loop will be called when a user hovers over the main unordered list.
document.onmouseover = superFly;
function superFly(e)
{
if (!e) var e = window.event;
var t = e.target || e.srcElement;
if(t.className == 'level1-li')
{
var kids = t.childNodes;
for(var i=0; i < kids.length; i++)
{
if(kids[i].className == 'level2-div')
{
kids[i].className = 'show';
break;
}
}
}
}
The first part of the JavaScript sets up the event listener.
document.onmouseover = superFly;
Next, I include a bit of code to make my function work in both standards-compliant browsers and in the non-standard Microsoft Internet Explorer (IE) browser.
function superFly(e)
{
if (!e) var e = window.event;
var t = e.target || e.srcElement;
A conditional statement limits the scope of the action to the unordered list.
if(t.className == 'level1-li')
{
I create a variable to represent the array of child nodes, and initiate a for loop.
var kids = t.childNodes;
for(var i=0; i < kids.length; i++)
{
As the loop cycles through the children, I check to see if the node in view is the div element that I want to act upon using a conditional statement.
if(kids[i].className == 'level2-div')
{
Finally, once the loop arrives at the desired child element, I take some action and break the loop, since there is no point in continuing to cycle through all of the child nodes.
kids[i].className = 'show'; break;
While there are certainly a number of ways to select child nodes, for relatively complex structures like a mega menu a for loop might just do the trick.
