(Totally changed my terrible answer. Let's try again.)
Let's assume you have the following base, cross-browser event methods:
var addEvent = window.addEventListener ? function (elem, type, method) {
elem.addEventListener(type, method, false);
} : function (elem, type, method) {
elem.attachEvent('on' + type, method);
};
var removeEvent = window.removeEventListener ? function (elem, type, method) {
elem.removeEventListener(type, method, false);
} : function (elem, type, method) {
elem.detachEvent('on' + type, method);
};
(Pretty simple, I know.)
Whenever you implement mouseenter/mouseleave, you just attach events to the
normal mouseover/mouseout events, but then check for two important particulars:
- The event's target is the right element (or a child of the right element)
- The event's relatedTarget is not a child of the target
So we also need a function that checks whether one element is a child of
another:
function contains(container, maybe) {
return container.contains ? container.contains(maybe) :
!!(container.compareDocumentPosition(maybe) & 16);
}
The last "gotcha" is how we would remove the event listener. The quickest way
to implement it is by just returning the new function that we're adding.
So we end up with something like this:
function mouseEnterLeave(elem, type, method) {
var mouseEnter = type === 'mouseenter',
ie = mouseEnter ? 'fromElement' : 'toElement',
method2 = function (e) {
e = e || window.event;
var target = e.target || e.srcElement,
related = e.relatedTarget || e[ie];
if ((elem === target || contains(elem, target)) &&
!contains(elem, related)) {
method();
}
};
type = mouseEnter ? 'mouseover' : 'mouseout';
addEvent(elem, type, method2);
return method2;
}
Adding a mouseenter event would look like this:
var div = document.getElementById('someID'),
listener = function () {
alert('do whatever');
};
mouseEnterLeave(div, 'mouseenter', listener);
In order to remove the event, you'd have to do something like this:
var newListener = mouseEnterLeave(div, 'mouseenter', listener);
// removing...
removeEvent(div, 'mouseover', newListener);
It's hardly ideal, but all that's left is just implementation details. The
important part was the if clause: mouseenter/mouseleave is just
mouseover/mouseout, but checking if you're targeting the right element, and if
the related target is a child of the target.