Борьба с onMouseout 2. Устранение мерцанияОтсебятина от 14 марта 2009 года. Теги: Javascript HTML
В прошлой статье я очень смутно описал возможности борьбы с мерцанием элемента с onMouseout в Firefox при передвижении курсора внутри элемента по его дочерним узлам, привязав его к конкретной задаче. На этот раз предложу пару способов для устранения внезапного пропадания элемента.
На самом деле, проблема проявляется не только в Firefox. Просто в других браузерах она не заметна. Но решения я буду предлагать только для Firefox, поэтому в других браузерах код может не работать. При желании, эти решения можно прикрутить и к другим браузерам.
Проведите мышкой во внутрь серого квадрата, а затем во внутрь появившегося желтого квадрата и обратно, в серый. Иногда желтый квадрат будет пропадать.
div
Смотреть код
<style type="text/css">
.parent {
width: 150px;
height: 100px;
border: 1px solid #000000;
background-color: #f8f8f8;
}
.child {
width: 100px;
height: 50px;
border: 1px solid #ff0000;
background-color: #fffdea;
margin: 15% auto 0 auto;
display: none;
}
</style>
<script type="text/javascript">
function show(bool) {
var div = document.getElementById("child");
if (bool)
div.style.display = "block";
else
div.style.display = "none";
/*
Если сделать просто div.style.display = (div.style.display == "none") ? "block" : "none";
то при первом запуске функции div.style.display будет равен "" и вложенный div будет показываться только когда мышка вне родительского div
*/
}
</script>
<center>
<div class="parent" onmouseover="show(true)" onmouseout="show(false)">
<!-- За пример взят textarea, потому что с элементами формы такой баг проявляется в 100% случаев -->
<textarea class="child" id="child">textarea</textarea>
div
</div>
</center>
Дело в том, что по умолчанию события, привязанные к элементу, "наследуются" его детьми (вложенными элементами). Как результат, когда мы наводим и выводим курсор из вложенного элемента, срабатывает обработчик события, который привязан к родителю, что приводит к мерцанию элемента или исчезновению вовсе (в зависимости от кода. В нашем случае элемент исчезает). Плюс ко всему, при наведении курсора на дочерний элемент, срабатывает onMouseout родительского.
Получается, что при наведении курсора на дочерний элемент, он исчезает, но тут же срабатывает функция onMouseover, "наследованная" от родителя и он тут же появляется, при выводе курсора из дочернего элемента он снова исчезает, благодаря "наследованной" у родителя onMouseout, а иногда и снова появляется. Более подробно изложен принцип чуть ниже.
Баг с мерцанием/исчезновением наблюдается не всегда и не со всеми элементами.
Javascript-событие возникает не на элементе, а на объекте window, которое выше body и document. Лишь после некоторых манипуляций оно приходит к элементу, к которому привязана функция-обработчик.
Пример #1 и его код:
<html>
<body onclick="op(event)">
<div>
<span>Кликни</span>
</div>
</body>
</html>
При клике по слову "кликни" создается событие в window, которое спускается по дереву, захватывая узлы (capturing):
document -> body -> div -> span
В последнем узле объект события достигает цели (at target) и далее начинает всплывать (bubbling) вверх:
span -> div -> body -> document -> window
При этом вызываются все события, привязанные к этим элементам. В нашем случае вызовется событие body, которое сообщит нам, каким элементом было вызвано событие (объект event хранит ссылку на своего "вызывателя").
Достаточно хорошо объясняет суть пример #2, где каждому узлу привязано событие.
Стоит отметить, что capturing и bubbling выполняются в зависимости от способа привязки события к элементу. Простая привязка через свойство или атрибут onClick выполняет только bubbling, а метод addEventListener(), в зависимости от третьего параметра, выполняет либо capturing (true), либо bubbling (false)
События в Javascript регистрируются по мере обработки. Если функция-обработчик предыдущего события не успела отработать, события не регистрируются.
Это и объясняет тот факт, что пропадает вложенный элемент не всегда. Когда курсор передвигается медленно, события успевают обрабатываться (при выводе курсора из вложенного элемента — onMouseout (bubbling), а за тем — onMouseOver (at target)), если курсор передвигать быстро, то второе событие зарегистрироваться не успеет и элемент пропадет.
|