Reputation: 904
What would be the best way to implement a mouseenter
/mouseleave
like event in JavaScript without jQuery? What's the best strategy for cross browser use? I'm thinking some kind of checking on the event.relatedTarget
/event.toElement
property in the mouseover
/mouseout
event handlers?
Like to hear your thoughts.
Upvotes: 13
Views: 7106
Reputation: 3139
another option is to distinguish true mouseout
events from fake (child-generated) events using hit-testing. Like so:
elt['onmouseout']=function(evt){
if (!mouse_inside_bounding_box(evt,elt)) console.debug('synthetic mouseleave');
}
I've used something like this on chrome and, caveat emptor, it seemed to do the trick. Once you have a reliable mouseleave event mouseenter is trivial.
Upvotes: 0
Reputation: 42496
(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:
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.
Upvotes: 14
Reputation: 681
John Resig submitted his entry to a contest, in which his was judged the best (Note: Dean Edwards was one of the jury). So, I would say, check this one out too.
Also its doesn't hurt to go thru jQuery, DOJO source once in a while, to actually see the best practices they r using to make it work cross-browser.
Upvotes: 1
Reputation: 13445
The best way, imho, is to craft your own event system.
Dean Edwards wrote one some years ago that I've taken cues from in the past. His solution does work out of the box however.
http://dean.edwards.name/weblog/2005/10/add-event/
Upvotes: 2