Источник: http://learn.javascript.ru/mousemove-events
В этой главе мы рассмотрим события, возникающие при движении мыши над элементами.
Событие mouseover происходит, когда мышь появляется над элементом, а mouseout — когда уходит из него.
В этих событиях мышь переходит с одного элемента на другой. Оба этих элемента можно получить из свойств объекта события.
event.target (IE: srcElement).event.relatedTarget (IE: fromElement)event.target (IE: srcElement).event.relatedTarget (IE: toElement).Как вы видите, спецификация W3C объединяет fromElement и toElement в одно свойство relatedTarget, которое работает, как fromElement для mouseover и как toElement для mouseout.
В IE это свойство можно поставить так:
function fixRelatedTarget(e) {
if (!e.relatedTarget) {
if (e.type == 'mouseover') e.relatedTarget = e.fromElement;
if (e.type == 'mouseout') e.relatedTarget = e.toElement;
}
}
Значение relatedTarget (toElement/fromElement) может быть null
Такое бывает, например, когда мышь приходит из-за пределов окна у mouseover будет relatedTarget = null.
Событие mousemove срабатывает при передвижении мыши. Но это не значит, что каждый пиксель экрана порождает отдельное событие!
События mousemove и mouseover/mouseout срабатывают с такой частотой, с которой это позволяет внутренний таймер браузера.
Это означает, что если вы двигаете мышью очень быстро, то DOM-элементы, через которые мышь проходит на большой скорости, могут быть пропущены.
Несмотря на некоторую концептуальную странность такого подхода, он весьма разумен. Хотя браузер и может пропустить промежуточные элементы, он гарантирует, что если уж мышь зашла на элемент (сработало событие mouseover), то при выходе с него сработает и mouseout. Не может быть mouseover без mouseout и наоборот.
Так что эти события позволяют надёжно обрабатывать заход на элемент и уход с него.
Представьте ситуацию — курсор зашел на элемент. Сработал mouseover на нём. Потом курсор идёт на дочерний… И, оказывается, на элементе-родителе при этом происходит mouseout! Как будто курсор с него ушёл, хотя он всего лишь перешёл на потомка.
Это происходит потому, что согласно браузерной логике, курсор мыши может быть только над одним элементом — самым глубоким в DOM (и верхним по z-index).
Так что если он перешел на потомка — значит ушёл с родителя.
Получается, что при переходе на потомка курсор уходит mouseout с родителя, а затем тут же переходит mouseover на него. Причем возвращение происходит за счёт всплытия mouseover с потомка.
События mouseenter/mouseleave похожи на mouseover/mouseout. Они тоже срабатывают, когда курсор заходит на элемент и уходит с него, но с двумя отличиями.
mouseenter, а затем — неважно, куда он внутри него переходит, mouseleave будет, когда курсор окажется за пределами элемента.События mouseenter/mouseleave не всплывают.
Для браузеров, в которых нет поддержки этих событий, можно повесить обработчик на mouseover/mouseout, а лишние события — фильтровать.
При mouseout можно получить элемент, на который осуществляется переход (e.relatedTarget), и проверить — является ли новый элемент потомком родителя. Если да — мышь с родителя не уходила, игнорировать это событие.
При mouseover — аналогичным образом проверить, мышь «пришла» с потомка? Если с потомка, то это не настоящий переход на родителя, игнорировать.
Посмотрим, как это выглядит, на примере кода:
<div style="padding:10px; margin:10px; border: 2px solid blue" id="outer">
<p style="border: 1px solid green">
Обработчики mouseover/mouseout стоят на синем родителе.
</p>
<blockquote style="border: 1px solid red">
..Но срабатывают и при любых переходах по его потомкам!
</blockquote>
</div>
<b id="info">Тут будет информация о событиях.</b>
<script>
var outer = document.getElementById('outer')
var info = document.getElementById('info');
outer.onmouseout = function(e) {
e = e || event;
var target = e.target || e.srcElement;
info.innerHTML = e.type+', target:'+target.tagName;
};
outer.onmouseover = function(e) {
e = e || event;
var target = e.target || e.srcElement;
info.innerHTML = e.type+', target:'+target.tagName;
};
</script>
У mouseover, mousemove, mouseout есть следующие особенности:
mouseove и mouseout — единственные, у которых есть вторая цель: relatedTarget (toElement/fromElement в IE).mouseout срабатывает, когда мышь уходит с родительского элемента на дочерний. Используйте mouseenter/mouseleave или фильтруйте их, чтобы избежать излишнего реагирования.mouseover, mousemove, mouseout могут пропускать промежуточные элементы. Мышь может моментально возникнуть над потомком, миновав при этом его родителя.События mouseleave/mouseenter поддерживаются не во всех браузерах, но их можно эмулировать, отсеивая лишние срабатывания mouseover/mouseout.