Как заставить потомков молчать или onmouseevent для DIV с вложенными тегами
Автор: adminCегодня я опять наткнулся на уже когда-то знакомые "грабли" в JavaScript и так как это произошло не в первый раз - я начал искать пример, того что я сделал в прошлый раз. Как обычно это бывает - я напрочь забыл где это могло быть в таком обширном коде прошлого проекта.
Кстати, о чём это я...?
Описание проблемы
Иногда, как оказалось - довольно часто - появляется необходимость во том, чтобы произвести какие-то действия по событию onmouseout для какого-то DIV элемента. Если в диве ничего не содержится или содержится только какой нибудь текст - то всё предельно просто - назначаем ему нужные события и все происходит так как нам хочется.
Но есть и проблематичная сторона этого вопроса - это случай, когда у нас в div - содержится один или несколько вложенных элементов (дочерних).
Так вот, в связи с тем, как браузер интерпретирует события вложенных элементов у нас появляется проблема ибо если навести курсор мыши на табличку или на картинку или на вложенный div то происходит событие onmouseout родительского div - это наверное правильно с точки зрения концепции браузеров, но не справедливо, когда человек пытается сделать хорошую вешь и у него появляется такая проблема. Таким образом, данное событие происходит не тогда и ине там где это нужно.
Пример такого случая:
<div onmouseover="over_handler()" onmouseout="out_handler()">
<img src="1.gif" >
<div>some text
<div>some text ....</div>
</div>
<table> ..... </table>
.............................
</div>
И я начал google'ить тему и параллельно составил эту заметку чтоб в следующий раз не тратить времени и чтоб кому-нибудь из вас, моих читателей, было удобнее разобраться в этом вопросе, если вдруг понадобится.
Так вот, я делал скроллирующийся ДИВ без самого скроллбара, а скроллинг (отличная тавтология) у него был исключительно за счёт положения мыши на главном контейнере. Кто видел как делается что-то подобное - понимает, что там даже при самом простом исходе - минимально 2 "дивизиона"(DIV-a). Но так как я делал эту штуку для передвижения по главному контенту страницы сайта (то есть по тексту страниц) - другого выхода у меня не было у меня было достаточное количество вложений различного характера.
В общем дело заключалось в том, чтобы либо заставить потомков заткнуться и не провоцировать события, либо научить их действовать как родители. И тут тоже - проблема отцов и детей. По-видимому эти качества у HTML от человека.
Решения
И я начал находить различные решения этой проблемы ибо мир так устроен, что если кто-то в одном конце мира наступил на грабли, то в другом конце мира в максимально короткий промежуток времени кто-то обязательно наступит на них же.
Решение №1. Не жалеем рук - жалеем голову.
Для всех вложенных элементов прописываем событие onmouseover="over_handler()". Таким образом, получаем срабатывание этого события постоянно то есть как будто мы и не делали out. Делать это достаточно просто, но есть и недостатки - трудоёмкость и невозможность в таких событиях в функции over_handler() использовать this.
Решение №2. Не жалеем браузер- жалеем себя.
Идея такая же как в предыдущем случае, но мы автоматизируем процесс. Дописываем функцию, которая сработает при инициализации окна и автоматически пройдясь по вложенным DOM элементам DIV - добавит для них событие onmouseover. Такая штука отличается от предидущего примера, так как менее трудоёмка, но при большом колличестве вложений будет значительно нагружать браузер при загрузке. Ещё один недостаток этого метода - я не написал эту функцию. Пока она мне не пригодилась. Но вы всегда можете сделать это сами. По моим подсчётам - это максимум 20 минут. Пишите и оставляйте в комментариях. Будут проблемы - постараюсь помочь.
Решение №3. Не жалеем миллисекунд времнени.
Можно использовать таймауты. То есть, когда наступает onmouseout мы вызываем его обработчик и с некоторой задержкой (таймаутом) (например и обычно это оптимально, 100 миллисекунд). Когда наступает onmouseover мы обрываем этот таймаут:
var t = null;
main_div.onmouseout = function() { t = window.setTimeout(mouseout_function, 100); }
main_div.onmouseover = function() { window.clearTimeout(t); }
Таким образом если мы намеренно не будем провоцировать задержку - то мы увидим, что события происходят правильно. Я в принципе в основном пользуюсь таким способом. Это и просто и достаточно универвсально.
Недостатки конечно тоже есть - во первых - это задержка в срабатывании функций. Но это для меня позволительно - 100 миллисекунд - не 100 лет.
Решение №4. Для "библиотекаря" Javascript.
Понравится это тем, кто привык использовать библиотеки для своих проектов и вместо того, чтоб написать что-то самому - любит побродить в поисках этого по просторам интернета. С использованием библиотеки под названием MouseEnter and MouseLeave смотрите демо и и скачивайте. Хорошая библиотека, но на сколько я понял - есть недостатки и баги в некоторых браузерах.
Делается это очень просто:
$('nash_div').observe('mouseover', myMouseEnterCallback.bindAsMouseEnter(scope, arg1, arg2));
Ну вот и всё.
Выбирайте то, что вам по душе и используйте.
Если будут вопросы и предложения - обращайтесь.
Жду ваших отзывов и комментов ПО ТЕМЕ.
С уважением,
Ваш Друм Бум.





Спасибо, очень помогло.Правда не совсем понятно, как юзать over_handler().
Ян,
всё очень просто, over_handler() никак использовать не надо – это событие которое вы бы хотели выполнить при mouseover на div и все его вложенные элементы. Прочтите внимательнее текст.
Отличная запись, спасибо. Также выбрал вариант с задержкой.
В моем случае нужно передавать параметры в функцию.
Вариант window.setTimeout(myFunc, 2500, arg1, arg2); не прокатил в IE (в опере нормально работает).
Погуглив наткнулся на кроссбраузерный вариант: window.setTimeout(function() {myFunc(arg1, arg2)}, 2500);
Огромное спасибо. Очень долго парился с этой проблемой, всякие ухищрения наворотил, оказалось все просто
Спасибо
Ребята пишут следующее:
То есть в родительском диве проверять источник события и выполнять функцию (в данном случае alert(1);) только когда источником является родительский див (this), но у меня не работает эта проверка…
Алексей,о каком случае Вы говорите, объясните подробнее.
И на всякий случай, попробуйте сделать alert(«hello») вместо 1 – бывает что булы не возвращаются алертом. И ещё один совет, для экспериментов с мышью используйте для дебага див а не алерт – так будет удобнее и достовернее.
К сожалению не отображается код, который я вставлял после «Ребята пишут следующее:»
Код не то чтобы не отображается, а он просто вырезается – попытайтесь сделать его менее похожим на JS – например попробуйте убрать начальный и конечный тэги script, если что – пишите мне на почту drumboom.net (лайка) gmail com