DOM Design Tricks II: A List Apart


DOM Design Tricks II: A List Apart
@import "/c/ala.css";
@import "/c/ala.css";
Skip navigation.
up frontarticlesabout alalive eventsxml feeds
ISSN: 1534-0295. 21 July 2000  Issue No. 73
Youre looking at an archive of old, outdated
material, maintained for historical reasons and to avoid linkrot.
Contents may have settled during shipping.
DOM Design Tricks II
by J. David Eisenberg
In this tutorial, well use the event-handling capabilities of
the Document Object Model (DOM) to make some minor improvements
to the expanding menu that we developed in a
previous tutorial.
[Truth in advertising: these improvements are borderline cute;
their real purpose is to serve as a vehicle to introduce the
concepts of events and nodes.]
In the previous tutorial, we discussed using the CSS display property to make an expanding
menu like the one below. In that tutorial,
only the small plus or minus sign images were clickable.
However, if you try the menu below, you'll see that all the
words in the main headings are active and clickable; not just the small
plus or minus signs. This wont work in Navigator 4.
Search Engines
Google
Yahoo!
Excite
Lycos
Web Design
Zeldman
Ask Tog
Jakob Nielsens Alertbox
Web Pages That Suck
Digital Photography
Steves Digicams
Imaging Resource
Digital Photography Review
Eisenbergs Photo Gallery
The original code used the onMouseOver and onMouseOut event handlers to detect when the mouse moved over the images.
Note: the code that well show in the text of this article is designed
to work with Mozilla, a DOM-compliant browser. If you want
code that will work on other browsers, you can use the
cross-platform DOM utilities include file,
which was developed in another article.
Using the View Page Source option in your browser will, of course,
show the actual code.
Before we go into the code, though, we have to discuss
the two ways that the DOM handles events:
Capturing and Bubbling Events
Aside from using onMouseOver and onMouseOut,
the DOM lets you attach an event listener to the objects
in your document. These listeners wait for events to occur,
and they can be told to listen for events in one of two ways.
The first method is known as event
capture; the second is called event bubbling.
Event Capture
Lets say that your document contains a <div> which
contains a <p> which contains an <img>.
Further, lets say you've added an event listener to all of them
using the capture method.
When a user clicks on the image, a mouseclick event occurs.
Even though the user clicked the image, the image doesn't get the
event first. Instead, the event listener attached to the document
grabs the event first and processes it. (That is, it captures
the event before it gets to its intended target.)
The event is then passed down to the <div>s event
listener. The event then goes to the <p>, and finally
to the <img>. That is, all of the clicked-on objects
ancestors higher up in the document capture the event
for processing before sending it down the chain to its intended
target.
You can
try event capture in a pop-up window.
(This only works in Mozilla.) [Ed. Note: Since this article was originally published, the event capture pop-up now works in most browsers.]
Event Bubbling
Now lets look at the same situation from the inside out. You have an
<img> inside a <p>, which is inside
a <div>, which is inside your document. We've attached
event listeners to all the objects, specifying the bubble
method. When a user
clicks the image, this time the events rise like a bubble in a glass
of water. The clicks original target, the
<img>, gets to see the event first, and
then passes it upwards to the <p> for further
processing, which passes it on
to the <div>, which finally passes it up to the
document. You can
try event bubbling
in a pop-up window.
(This only works in Mozilla.) [Ed. Note: Refer to previous Editors Note.]
Here are the
relevant parts of the source code for both demos.
Setting Events
Now that we know how the DOM handles events, we have to find
out how to add event listeners to objects.
well tell each <div>
in the menu headings to listen for mouse click, mouse over, and mouse out
events.
To make it easier to set the event listeners, well need a utility
routine that gives us back a reference to an object in a
document when we give the objects name. This function uses
variable isNav6, which is part of the
DOM Utilities
package introduced in an earlier tutorial.
function getObject( objName )
{
if (isNav6)
{
return document.getElementById( objName );
}
}
Once we have the object, we can add an event listener with a
statement of this form:
obj.addEventListener( "name", functionName, useCapture );
where:
nameis the name of the event you want the object to listen forfunctionNameis the name of the function that will process that eventuseCaptureis a boolean that tells whether you want to use event
capturing (true) or event
bubbling (false).
So, what looks like this in HTML:
<div id="m0"
onMouseOver="highlight()">
...is achieved like this when using the DOM:
var obj = getObject("m0");
obj.addEventListener( "mouseover", highlight, false );
We use the getObject function from above to write a
setup() function to add the event
listeners to each of the menu <div>s, which
have ids of m0, m1, and m2.
var nMenus = 3;
function setup( )
{
var i;
var obj;
for (i=0; i < nmenus; i++)
{
obj = getObject("m" + i);
if (isNav6)
{
obj.addEventListener("mouseover", highlight, false);
obj.addEventListener("mouseout", dim, false);
obj.addEventListener("click", showMenu, false);
}
}
}
Now, we have to write the highlight(), dim(), and
showMenu() functions. In order to do this, we must first
understand the concept of a Node.
Nodes
As we detailed in a previous article,
your documents are made up of spare parts that are nested
inside one another. This HTML...
<body>
<p>
First Text
<img src="picture.png">
<i>More Text</i>
</p>
</body>
...has this structure:
A <body>, which contains
A paragraph (<p>), which contains
the First Text
an image (<img>)
and an italic (<i>) element which contains
More Text
When CSS-compliant browsers read your HTML files, they analyze
this structure and create a structure of nodes, which you
can think of as little chunks of information that describe your
document. The nodes for the HTML above can be diagrammed
as shown below. The top half of each node shows
the nodeName, and the bottom half shows
the nodeValue. You can click the diagram to open up a window
that shows a larger version.
Nodes also contain information about their relationship to each other.
Lets look at these nodes as if they were members
of a family tree.
Node Bs
parentNode is node A.
Node Bs firstChild is
node C, and
its lastChild is node E.
Node B also contains a
childNodes array that lists all its immediate
children, C,
D, and E).
Node D has a previousSibling,
which is node C, and a nextSibling,
node E.
Since node C
has nobody to its left and nobody immediately below it,
its previousSibling and
firstChild properties will both be null.
You may explore these relationships
more fully in a new pop-up window.
We're going to use the ability to move through this family
tree of a documents nodes to find out which
<div> a user clicked in the expanding menu.
For a quick quiz on nodes,
see if you can answer these questions:
Who is node Fs
parentNode?
Who is node As
firstChild?
Who are node Bs
nextSibling and previousSibling?
See the answers
Node E is node
Fs parent.
Node B is
As firstChild
(and also its lastChild).
Node B is an only
child, so its previousSibling and
nextSibling are null.
Finding the <div>
When an event occurs, the corresponding event listener function
is invoked. This function should be written to expect one
argument  an Event object.
The events target property is the one we're interested in;
it tell us which Node is the events intended target.
When we click the words or the image in a <div>, the
target that gets returned is actually the text or
the image inside the
<div>, not the <div> itself.
[The events currentNode property is the one we really want, but
its not implemented in Mozilla release 15.]
Therefore, we have to write a function which checks to see if
the target of the event we pass to it is
a DIV element (tag). If not, the
function keeps looking at that nodes parentNode,
and its parent, and
so forth, until it finds a DIV element.
function findOwner(evt)
{
var node = evt.target;
while (node)
{
if (node.nodeType == Node.ELEMENT_NODE &&
node.nodeName == "DIV")
{
return node;
}
node = node.parentNode;
}
return null;
}
Once we have the <div>s node,
we can change its properties, which well
need to do for the highlight() and dim() functions.
Notice that we change the shape of the cursor when it
moves over the <div>. [This does not work
in Internet Explorer.]
function highlight(evt)
{
var obj = findOwner(evt);
if (isNav6) { obj.style.cursor = "pointer"; }
obj.style.color= "#ff0000"; // red
}
function dim(evt)
{
var obj = findOwner(evt);
if (isNav6) { obj.style.cursor = "default"; }
obj.style.color = "#000000"; // black
}
Implementing showMenu()
All that remains now is to implement the showMenu()
function, which expands and contracts the menu.
The line numbers in the code below are for reference only.
1 function showMenu(evt)
2 {
3 var owner = findOwner(evt);
4
5 var divNum;
6
7 divNum = owner.attributes.getNamedItem("id").nodeValue;
8
9 divNum = parseInt(divNum.substr(1));
10
11 if (getIdProperty("s" + divNum, "display") != "block")
12 {
13 setIdProperty("s" + divNum, "display", "block");
14 document.images["i" + divNum].src = "minus.png";
15 }
16 else
17 {
18 setIdProperty("s" + divNum, "display", "none");
19 document.images["i" + divNum].src = "plus.png";
20 }
21 }
Here are the lines of interest:
Line 3
As in the highlight() and dim() functions,
we first have to find the owner of the click
event.
Line 7
A nodes attributes property gives a list of
all the tags attribute=value pairs. Its
indexed by string, so we need to use the getNamedItem()
method to find the id attributes value (given by
the nodeValue property).
Line 9
Since we've cleverly named all the <div> tags
with ids like m0, m1, etc., we use
the substr method to extract the digit.
Line 11
Checks to see if a submenu is already displayed by
looking at its display property.
Lines 13-14, 18-19
We've also numbered the ids of the submenus and
the images, so its easy to change their properties and
image sources.
Its a lot of code, but once you understand it, you'll be prepared
to manipulate nodes for very powerful effects. Lets summarize:
Summary
You use the addEventListener() function to make
a document object react to events rather than having to use
onEvent= handlers in the tags. You may look at
these events as they are passed down from the document to the
the target (capture), or as they are passed up from the target
to its enclosing elements (bubbling).
When the event listener function is invoked, you get an Event
object that tells you the target for which the event was
destined. This target may not always be the object whose properties
you wish to affect, so it might be necessary to walk through the target
nodes family tree until you find the node you want.
Being able to attach event listeners to a documents objects
is a great convenience; knowing how to exploit the hierarchy
of a documents nodes gives us immense power. well learn more
about that in the next tutorial.
J. David Eisenberg
is a programmer and teacher living in San Jose, CA with his cat, Marco
Polo. Most of his current work is in XML, Java, JavaScript, and Perl.
He has written a book about Scalable Vector Graphics. The details are at catcode.com/narrative.html.
BookmarkPermanent URI.
Design an expanding menu with the W3C standard Document Object Model (DOM).
Search
Include Discussions
Related Topics
DesignDOM | Scripting
Departments
Contact
Contribute
Credits
Permissions
Q & A
Hot Topics
Accessibility 35
Browsers | X-Platform 28
Business 41
Content 43
CSS 51
Culture 41
Design 73
DOM | Scripting 20
Flash 9
HTML | XHTML 41
Process 23
Server-Side 19
Tools 22
Typography 10
Usability 21
XML & Pals 12
ALA lives at Logicworks.Basecamp: Elegant web-based project management for freelancers, designers, and creative services firms.
Copyright © 19982004 A List Apart Magazine, Happy Cog Studios, and the authors. XHTML, CSS, 508.
содержание | 2 | Amway в россии, полезная информация о продукции от Эмвей, amway ru
Используются технологии uCoz