I prepared a little example of the various event registration models, event properties and event orders. Thus you can get a quick overview of the possibilities and restrictions of event handling.
The mouse events are by far the most important events. On this page I introduce some of the most common problems and tricks.
We’ll go through all mouse events: mousedown, mouseup and click, dblclick, mousemove and finally mouseover and mouseout. Then I explain the relatedTarget, fromElement and toElement event properties. Finally the Microsoft proprietary mouseenter and mouseleave events.
For browser compatibility, see the Events page.
Here’s a small example. Try it to better understand the explanations below.
Mousedown, mouseup, click and dblclick are registered to the link.
You’ll see the events that take place in the textarea, or in an alert, if you
so choose.
The event handlers are registered on this link.
Clear textarea.
If the user clicks on an element no less than three mouse events fire, in this order:
mousedown
, user depresses the mouse button on this elementmouseup
, user releases the mouse button on this elementclick
, one mousedown
and one mouseup
detected
on this elementIn general mousedown
and mouseup
are more useful than
click
. Some browsers don’t allow you to read out mouse button information
onclick
.
Furthermore, sometimes the user does something with his mouse but no click
event follows.
Suppose the user depresses the mouse button on a link, then moves his mouse off the link
and then releases the mouse button. Now the link only registers a mousedown
event. Similarly, if the user depresses the mouse button, then moves the mouse over a link
and then releases the mouse button, the link only registers a mouseup
. In neither
case does a click
event fire.
Whether or not this is a problem depends on the user interaction you want. But
you should generally register your script onmousedown/up
,
unless you’re completely sure you want the click
event and nothing else.
If you use alerts in handling these events, the browser may lose track of which event took place on which element and how many times it took place, messing up your scripts. So it’s best not to use alerts.
The dblclick
event is rarely used. Even when you use it,
you should be sure never to register both an onclick
and an ondblclick
event handler on the same HTML element. Finding out what the user has actually done is nearly impossible
if you register both.
After all, when the user double–clicks on an
element one click
event takes place before the dblclick
. Besides,
in Netscape the second click
event is also separately handled before the
dblclick
. Finally, alerts are dangerous here, too.
So keep your click
s and dblclick
s well separated to avoid
complications.
The mousemove
event works fine, even in Netscape 4, but you should be aware
that it may take quite some system time to process all mousemove events. If the user
moves the mouse one pixel, the mousemove
event fires. Even when
nothing actually happens, long and complicated functions take time and this
may affect the usability of the site: everything goes very slowly, especially on old computers.
Therefore it’s best to register an onmousemove
event handler only when
you need it and to remove it as soon as it’s not needed any more:
element.onmousemove = doSomething; // later element.onmousemove = null;
This is one of the few cases in which Netscape 4’s model is actually useful. Capture the mouse event when you need it and release it when you don’t need it any more. You don’t need to re–define the event handler.
element.onmousemove = doSomething; element.captureEvents(Event.MOUSEMOVE); // later element.releaseEvents(Event.MOUSEMOVE);
Take another look at the example, switch the mouseovers on and try them.
The example adds an onmouseover
event handler to ev3
only. However,
you’ll notice that (except in Netscape 4) a mouseover event takes place not only when the mouse enters
ev3
's area, but also when it enters the area of ev4
or the
span
. In Mozilla before 1.3, the event even fires when the mouse enters the area of a text!
The reason for this is of course
event bubbling. The user causes a
mouseover
event on ev4
. There is no onmouseover
event handler on this element, but there is one on ev3
. As soon as the event
has bubbled up to this element, the event handler is executed.
As to Netscape 4, I’m not sure why it behaves as it does.
Now this setup, though completely correct, gives us some problems.
Our first problem is targeting. Suppose the mouse enters ev4
:
----------------------------------------- | This is div id="ev3" | | ----------------------------- | | | This is div id="ev4" | | | | -------- <-------- | | | | span | | | | | | | | | | | -------- | | | ----------------------------- | ----------------------------------------- <--------: mouse movement
Now the target/srcElement
of this event is ev4
: it’s the
element the event took place on, since the user mouses over it. But when this happens:
----------------------------------------- | This is div id="ev3" | | ----------------------------- | | | This is div id="ev4" | | | | -------- | | | | | span | | | | | | --------> | | | | -------- | | | ----------------------------- | ----------------------------------------- -------->: mouse movement
the event has exactly the same target/srcElement
. Here, too, the mouse enters
ev4
. Nonetheless you might want do one thing when the mouse comes from
ev3
and another thing when it comes from the SPAN. So we need to know where
the mouse comes from.
W3C added the relatedTarget
property to mouseover and mouseout
events. This contains the element the mouse came from in case of mouseover
, or
the element it goes to in case of mouseout
.
Microsoft created two properties to contain this information:
fromElement
refers to the element the mouse comes from. This is interesting
to know in case of mouseover.toElement
refers to the element the mouse goes to. This is interesting
to know in case of mouseout.In our first example, relatedTarget/fromElement
contains a reference to
ev4
, in our second example to the SPAN. Now you know where the mouse came from.
So if you want to know where the mouse comes from in case of mouseover
, do:
function doSomething(e) { var relTarg; if (!e) var e = window.event; if (e.relatedTarget) relTarg = e.relatedTarget; else if (e.fromElement) relTarg = e.fromElement; }
If you want to know where the mouse goes to in case of mouseout
, do:
function doSomething(e) { var relTarg; if (!e) var e = window.event; if (e.relatedTarget) relTarg = e.relatedTarget; else if (e.toElement) relTarg = e.toElement; }
When using mouseover and mouseout sometimes we don’t want to be bothered
with event bubbling. For instance, in a layer-based navigation you may need to know when the mouse
leaves a layer so that it can be closed. Therefore you register an onmouseout
event
handler to the layer. However, you don’t want to be bothered by the internal
mouseouts on the actual links.
-------------- | Layer |.onmouseout = doSomething; | -------- | | | Link | ----> We want to know about this mouseout | | | | | -------- | | -------- | | | Link | | | | ----> | but not about this one | -------- | -------------- ---->: mouse movement
So how do we reject any mouseout that does not take place on the layer the event handler is registered to, any mouseout that bubbles up from the links?
The solution is to see if the target/srcElement
of the event is the same element
as the element the event handler has been registered to (in our case, the navigation layer).
As will be explained later on, you can usually find this element by using the
the this
keyword.
If target/srcElement
refers to the same HTML element as this
,
the user has moved his mouse out of the actual layer. If it doesn’t refer to the
same element the user has caused an internal mouseout that should be ignored.
To detect this, you could do:
function doSomething(e) { if (!e) e = window.event; if (e.target) var trg = e.target; else if (e.srcElement) var trg = e.srcElement; if (trg != this) return // Mouseout on links, ignore event // Mouseout took place on layer // Handle event }
Microsoft has another solution. It has created two new events mouseenter
and mouseleave
. They are almost the same as mouseover and mouseout except that
they don’t react to event bubbling. Therefore
they see the entire HTML element they’re registered to as one solid block and don’t
react to mouseovers and –outs taking place inside the block.
So using these events solves our problem too: they react only to mouseovers/outs on the element they’re registered to.
At the moment these events are only supported by Explorer 5.5 on Windows and higher. Maybe the other browser vendors will copy these events.