Opera/IE баг с очередью обработки события несколькими элементами (напр onmouseover)
Нашел такой баг - если в ячейке таблицы есть внутри элементы, например, div, который занимает всю ячейку TD и для td задана функция onmouseover, а для div не задана нигде и никак, то в процессе обработки этой функции onmouseover в ней каким то чудом в качестве Event.srcElement фигурирует div хотя для него, повторюсь, не была никоим образом задана функция onmouseover. Этот баг есть и в ИЕ и в Опере, в опере он я бы сказал пожесче.
элементы кода: так выглядит ячейка таблицы: <td><div class="rc"><div class="dgr" onclick="f1(...);">X</div>123<br><b>Текст1</b><br>Текст2</div></td> onmouseover всем ячейкам таблицы задает функция так (срабатывает при загрузке страницы): в цикле пробегаем по всем ячейкам и <цикл> ... if(td.attachEvent) { td.attachEvent('onmouseover', HighLightTD); td.attachEvent('onmouseout', HideTD); } if(td.addEventListener) { td.addEventListener('mouseover', HighLightTD, true); td.addEventListener('mouseout', HideTD, true);} ... Функции HighLigtTD и HideTD соотв подсвечивают или убирают подсветку с ячейки таблицы. Но не только. Подсветка/Хайд изначальна в Опере тоже глючили из-за описываемого бага. Но с этим я справился. Самый главный баг в том что функции HighLightTD/HideTD срабатывают и на наведение на внутренний div ячейки таблицы, хотя для них не устанавливались. Создается впечатление что это наследование внутренним дивом функции onmouseover ячейки таблицы td. Ну для большей ясности function HighLightTD(e) { if(!e) var e = window.event; if(e.srcElement) td = e.srcElement; else td = e.currentTarget; // !! для проверки делаем алерт alert(td.tagName); // и в этом алерте какимто чудом появится DIV хотя, повторюсь, на DIV эта функция не вешалась ... } итак: <td onmouseover=...> <div> .. </div> </td> наводим мышку на td сначала будет алерт с тэгом TD, а после сразуже с DIV Помогите с этим разобраться, как исключить обработку события onmouseover для внутреннего div'a ячейки таблицы? Да в Файрфокс всё прекрасно работает. |
Почитайте статью про события мыши на этом сайте, там упоминается об этом.
|
Одну из самых нужных особенностей DOM назвать багом -- это сильно :)
|
Багом называю потому как привык к самой правильной и ожидаемой, в большинстве случаев, обработке ХТМЛ/ДОМ/Ява со стороны ФайрФокс. И в этом случае он работает ожидаемо и правильно ИМХО. Не подскажите конкретную статейку? Я в общем то знаком более-менее с этой темой, и перед созданием темы поискал похожее но ответов не нашел :\
|
Порядок срабатывания событий, а вообще было бы полезно всю статью прочитать для понимания механизма.
|
Уже прочитал и в общем-то этот механизм я знал (читал до этого на английском поэтому статья на русском + хорошо сделанные примеры более объяснили некоторые тонкости), НО! Это помогло понять более точнее природу БАГа в Опере, но всё же не то как этот баг победить. Баг тут, имхо, заключается в том что событие onmouseover родительского элемента срабатывает, затем срабатывает onmouseover дочернего и тут же - onmouseout родительского (такое впечатление) как будто бы событие дойдя до потомка (всплытие - bubble) ввело "мышь" в заблуждение, и она "подумала" что она уже ушла с элемента-родителя TD и запустился обработчик onmouseout. Это даже заметно - подсветка мелькает и тут же пропадает! Если сделать обычную подсветку бэкграунда родительского элемента, с учетом его текущего цвета (т.е. при подсветке (onmouseover) сохранять текущий цвет фона родителя, а потом его восстанавливать onmouseout) Вы увидите этот баг, т.к.
1. onmouseover - сделали цвет фона родителя color_new, сохранили цвет родителя в last_color 2. идет второй onmouseover, для внутреннего дива (как на этом этапе выявить что srcElement не тот что нам нужен и пропустить обработку функции? проверка srcElement.tagName как-то не помогает, это один важный вопрос, но его можно, при решении вопроса с подсветкой, обойти по-другому) 3. тут же срабатывает onmouseout для родителя (TD) - родителю вернули его старый цвет last_color В итоге пробегаясь по таблице где в каждой ячейке есть внутренний див, который и делает этот баг, у нас ничего не подсвечивается - иногда заметно как ячейка очень быстро моргает, подсвечивается и тут же пропадает подсветка. Я не могу понять почему происходит этот onmouseout когда мышь еще находится на элементе? Не баг ли это? |
Еще раз подумав: самый главный вопрос
из статьи: Цитата:
|
Цитата:
/** * Объявляем и сразу вызываем функции, * чтоб не проверять поддержку методов * каждый раз: */ var addEventListener = function() { // Если браузер IE: if (window.attachEvent) // Возвращаем функцию для IE: return function(element, event, callback) { // Фиксуем callback, чтоб установить правильный // this, и передавать объект события первым параметром: callback.__callbackfix = function() { callback.call(element, window.event); }; // Устанавливаем обработчик (не забываем про "on") return element.attachEvent("on" + event, callback.__callbackfix); } // Если браузер W3C-совместим: if (window.addEventListener) // Возвращаем функцию без фиксов: return function(element, event, callback) { // Последний параметр всегда false, для совместимости с IE: return element.addEventListener(event, callback, false); } }(); var removeEventListener = function() { // Если браузер IE: if (window.detachEvent) return function(element, event, callback) { // Удаляем наш сохраненный в функции фикс: return element.detachEvent("on" + event, callback.__callbackfix); } // Если браузер W3C-совместим: if (window.addEventListener) return function(element, event, callback) { // Удаляем без фиксов: return element.removeEventListener(event, callback, false); } }(); Он избавляет от всех проблем несовместимости, кроме тех, которые связаны с различными свойствами объекта события. Но теперь, по крайней мере, в IE будет возможность удалять callback с фиксом "прозрачно". |
Всем спасибо вроде разобрался с проблемой.
Для оперы просто изменил проверку на srcElement и поставил его на второе место, а на первое место currentTarget, который у последней оперы есть (давно ли?). А вот для IE пришлось делать обертку по типу того что я писал и Андрей Параничев, и вставлять в функцию оригинальный элемент вызова функции, т.е. TD + помогла статья с замыканиями. Тему вроде можно закрывать. |
Часовой пояс GMT +3, время: 00:36. |