In order to implement mouse rollovers such as the one you see
at the right, we will need two new event handlers:
onmouseover and
onmouseout. (You are
already familiar with onclick.) The
mouseover event occurs whenever the mouse is over
an element; the mouseout
event occurs when the mouse leaves that element.
In Netscape 4 and Internet Explorer 3, only hypertext links could react to these events. Let’s start with an example that will change the background color when we move the mouse over the links below:
Here’s the markup:
<a href="#" onmouseover="document.bgColor='#ffcc99';"
onmouseout="document.bgColor='white'">Peach</a> |
<a href="#" onmouseover="document.bgColor='#99ccff';"
onmouseout="document.bgColor='white'">Light Blue</a> |
<a href="#" onmouseover="document.bgColor='#ff99cc';"
onmouseout="document.bgColor='white'">Neon Pink</a>
Image objectYou learned about image objects in assignment two, where
you listed the src property of each of
the images in the document.images array. It turns out
that you can not only read the src property, you can also
set it. When you set the src property of an image, this
causes the server to send you the image (if it’s not already
cached), and replace the existing image with the new image. It’s
as if you changed the src= attribute of the
<img> element. Let’s see this in action. The
image below is the second image on the page:

Here is the HTML:
<img src="rollover/blackdot.png" width="100" height="100"
alt="black dot" />
<form action="#">
<input type="button" value="Red"
onclick="change1('rollover/reddot.png')" />
<input type="button" value="Black"
onclick="change1('rollover/blackdot.png')" />
</form>
Here is the JavaScript change1( ) function:
function change1( newSource )
{
document.images[1].src = newSource;
}
Now let’s combine the mouseover and the image. When you mouse over the image at the right, the colors and shapes will flip. Here’s the HTML:
<a href="#" onmouseover="change2('rollover/colorflip2.png')"
onmouseout="change2('rollover/colorflip.png')">
<img src="rollover/colorflip.png" width="100" height="100"
alt="red square, blue dot" border="0" /></a>
And here’s the JavaScript. Notice that we need a different function, since the image we are manipulating has an index number 2 on this page.
function change2( newSource )
{
document.images[2].src = newSource;
}
Well, you might be thinking, why not make a generic change function like this:
function change( whichImage, newSource )
{
document.images[whichImage].src = newSource;
}
and use it as on this page (and yes, you should look at it and figure out how it works!)
Even though this works, it’s not a good technique, because it is
dependent on the order of the pictures. If you decide to switch the
red and yellow pictures, the HTML will have to change. If you were
to add a “cyan” picture at the left, you’d have to
change the numbers in all the other <a href...>
elements.
nameThe obvious answer is to give each image a name=
attribute, and use the name. After all, that’s what we did
to make access to forms easier. If you give a name to each
image, you end up with HTML that looks something
like this:
<a href="#" onmouseover="change('redImg', 'rollover/red1.jpg')"
onmouseout="change('redImg', 'rollover/red0.jpg')"><img src="rollover/red0.jpg"
name="redImg" width="100" height="100" alt="Red" /></a>
<a href="#" onmouseover="change('yellowImg', 'rollover/yellow1.jpg')"
onmouseout="change('yellowImg', 'rollover/yellow0.jpg')"><img src="rollover/yellow0.jpg"
name="yellowImg" width="100" height="100" alt="Yellow" /></a>
<-- etc. -->
But this leads to a problem in our function. The following code will not work.
function change( imageName, newSource )
{
document.imageName.src = newSource;
}
Let’s see what happens when the mouse rolls over the “Red”
link. The onmouseover handler tells JavaScript to invoke the
change( ) function, and passes redImg as the
imageName parameter and rollover/red1.jpg as the
newSource parameter. But the assignment statement says to
change the source for an image whose name is imageName,
not “what’s in the imageName parameter.”
What the code really has to say is
document.whatever-is-in-imageName.src = newSource.
There are two ways to achieve this effect.
eval( ) methodThis method is the one you’ll see in most rollover scripts. The way it works is to create a string whose content is the command you want to execute. Then you have to tell JavaScript, “OK - take that string and evaluate it as if I had typed it into the script in the first place.” The function will look like this:
function change( imageName, newSource )
{
var command;
command = "document." + imageName + ".src = newSource";
eval(command);
}
Let’s look at the “Red” link again. The parameters
get passed as before. The assignment statement will now create a string
that works out to document.redImg.src = newSource. That’s
the statement that you really want to do. eval(command); tells
JavaScript to do that statement. See it
in action.
I personally don’t like the eval( ) method.
My main objection is that it’s a pain to construct the string
correctly. I also note that eval( ) is an
“expensive” function—it takes time to parse the string
you’ve constructed, and there’s a fair amount of overhead
involved in that process. Realistically, this won’t impact the
performance of your JavaScript, since the extra time is far overshadowed
by the time required to download and/or display the image. It’s just
the principle of the thing.
There’s another method to get the image switching, and it depends upon the little-known fact that JavaScript arrays are associative arrays. Not only can you index an array by number, you can also index an array by name.
When the browser sees an <img> element in your
HTML document, it not only adds an entry to the images
array; it also adds an associative entry to the images
array, using the name= attribute as the index. The first
image on this page has a name="evclogo" attribute. That
means that all of the following will refer to the src of
that image:
document.images[0].src (the “number” method)document.evclogo.src (direct use of a name)document.images["evclogo"].src (the associative method)With this knowledge, we can write the function for the version of the rollover script that uses associative arrays, which you can see in action here.
function change( imageName, newSource )
{
document.images[imageName].src = newSource;
}
Consider this: You’re using a slow Internet connection, and you’re on a page with a mouse rollover. You put the mouse on the button...and wait for a few seconds as the other image downloads. We can make this situation better by preloading the highlighted images.
In the <head> of the document, we will
create a an array to hold the “highlighted” images
and immediately start loading them. To make the code shorter,
we will use another array with the file names.
var onImageURL = new Array( // the "on" images
"rollover/red1.jpg",
"rollover/yellow1.jpg",
"rollover/green1.jpg"
);
var preload = new Array( onImageURL.length );
var imgNum; // a loop counter
The body of the following loop does two things:
Image object in memory. You can
think of this as if the browser creates an
<img src="" /> element in memory. It’s not
in the document, so no new image appears on the screen.src of the in-memory image is set to the filename
we want to preload. When the source changes, the browser either loads the
image from cache, or if it isn’t cached, sends a message to the
server asking it to download.
for (imgNum = 0; imgNum < preload.length; imgNum++)
{
preload[imgNum] = new Image( );
preload[imgNum].src = onImageURL[imgNum];
}
Note that we use preload.length in the test for
the loop. That way, we can preload as many images as we want
without having to change the loop code.
All of this code happens in the <head> of the
document, outside of a function. It occurs before the text of the page even begins to
appear. Once the body of the page starts loading, some (if not all) of the
rollover images are on their way from the server. The rest of the page
stays exactly as it was. You may
see it in action. Since
you have probably already loaded these images from the other demos, you
won’t see any difference in speed. Trust me, though; it does make
a difference.
You may be concerned that there’s a lot of text involved in
duplicating the image name and the URLs in the onmouseover and
onmouseout attributes. Well, as long as there is an array
for the images that you want to preload, and it has the “on”
URLs in it, why not add a second array with the URLs of all the
“off” images, and a third array with the names of the
images? Here’s what it looks like:
var onImageURL = new Array(
"rollover/red1.jpg",
"rollover/yellow1.jpg",
"rollover/green1.jpg"
);
var offImageURL = new Array(
"rollover/red0.jpg",
"rollover/yellow0.jpg",
"rollover/green0.jpg"
);
var imgName = new Array(
"redImg",
"yellowImg",
"greenImg"
);
As long as three arrays stay in step with one another, this
approach works wonderfully well. Our preloading code remains the same,
but we now have a new function for highlighting images. Our function will
take an imageNumber
which is an index into our arrays, and a boolean
variable named turnOn which tells whether to turn the
image on or off:
function highlight( imageNumber, turnOn )
{
var theURL;
var theName;
theName = imgName[ imageNumber ];
if (turnOn)
{
theURL = onImageURL[ imageNumber ];
}
else
{
theURL = offImageURL[ imageNumber ];
}
document.images[theName].src = theURL;
}
Now we change the HTML to look like this. Notice that the JavaScript is much more compact.
<a href="#" onmouseover="highlight(0, true)"
onmouseout="highlight(0, false)"><img src="rollover/red0.jpg"
name='redImg' width="100" height="100" alt="Red" /></a>
You are probably thinking, “Why is he going back to using numbers? What happens if we change the order of the pictures? What happens if we need to add a new picture? Won’t we have to recode everything?”
No, you won’t. This time we aren’t using the built-in
document.images array, whose numbering changes every time we
rearrange or add images. Instead, we’re using the arrays that
we constructed ourselves, and over which we have complete control.
If you look at the
example, you will see that we have added a picture at the
left and rearranged
two of the other colors. Look carefully at the HTML; the numbers used in the
calls to highlight match the order in the arrays in the
script. When we add new images, we just add them at the end of all
the arrays—it doesn’t matter where they land on the screen.
There are many other ways to do mouse rollovers. They truly are the
“cole slaw of the Internet,” with a wide variety of
recipes ranging from the really wonderful to the really awful. Here’s
one other variation. It presumes that you are basing the URLs for
the on and off images on the image’s name attribute:
If you have an image with name="xyz", then the
“off” image will be file
directory/xyz0.jpg
and the “on” image will be file
directory/xyz1.jpg
Take a look at the result. The function now gets the image name as its first parameter, not the number in the array. This method requires a little bit of extra text in your HTML, but it relies on names instead of numbers. This makes it easier to read, and that makes people feel better.