Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 07.03.2009, 06:13
no. no. вне форума
Новичок на форуме
Отправить личное сообщение для no. Посмотреть профиль Найти все сообщения от no.
 
Регистрация: 16.08.2008
Сообщений: 9

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 ячейки таблицы?

Да в Файрфокс всё прекрасно работает.

Последний раз редактировалось no., 07.03.2009 в 06:14. Причина: дополнение
Ответить с цитированием
  #2 (permalink)  
Старый 07.03.2009, 12:56
...
Отправить личное сообщение для Zibba Посмотреть профиль Найти все сообщения от Zibba
 
Регистрация: 13.10.2008
Сообщений: 225

Почитайте статью про события мыши на этом сайте, там упоминается об этом.
Ответить с цитированием
  #3 (permalink)  
Старый 07.03.2009, 13:24
Новичок на форуме
Отправить личное сообщение для Kolyaj Посмотреть профиль Найти все сообщения от Kolyaj
 
Регистрация: 19.02.2008
Сообщений: 9,177

Одну из самых нужных особенностей DOM назвать багом -- это сильно
Ответить с цитированием
  #4 (permalink)  
Старый 07.03.2009, 14:27
no. no. вне форума
Новичок на форуме
Отправить личное сообщение для no. Посмотреть профиль Найти все сообщения от no.
 
Регистрация: 16.08.2008
Сообщений: 9

Багом называю потому как привык к самой правильной и ожидаемой, в большинстве случаев, обработке ХТМЛ/ДОМ/Ява со стороны ФайрФокс. И в этом случае он работает ожидаемо и правильно ИМХО. Не подскажите конкретную статейку? Я в общем то знаком более-менее с этой темой, и перед созданием темы поискал похожее но ответов не нашел :\
Ответить с цитированием
  #5 (permalink)  
Старый 07.03.2009, 14:36
...
Отправить личное сообщение для Zibba Посмотреть профиль Найти все сообщения от Zibba
 
Регистрация: 13.10.2008
Сообщений: 225

Порядок срабатывания событий, а вообще было бы полезно всю статью прочитать для понимания механизма.
Ответить с цитированием
  #6 (permalink)  
Старый 07.03.2009, 15:23
no. no. вне форума
Новичок на форуме
Отправить личное сообщение для no. Посмотреть профиль Найти все сообщения от no.
 
Регистрация: 16.08.2008
Сообщений: 9

Уже прочитал и в общем-то этот механизм я знал (читал до этого на английском поэтому статья на русском + хорошо сделанные примеры более объяснили некоторые тонкости), НО! Это помогло понять более точнее природу БАГа в Опере, но всё же не то как этот баг победить. Баг тут, имхо, заключается в том что событие 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 когда мышь еще находится на элементе? Не баг ли это?

Последний раз редактировалось no., 07.03.2009 в 15:29.
Ответить с цитированием
  #7 (permalink)  
Старый 07.03.2009, 15:51
no. no. вне форума
Новичок на форуме
Отправить личное сообщение для no. Посмотреть профиль Найти все сообщения от no.
 
Регистрация: 16.08.2008
Сообщений: 9

Еще раз подумав: самый главный вопрос
из статьи:
Цитата:
При установке обработчиков методами attachEvent/detachEvent this внутри обработчика всегда указывает на объект window и совершенно бесполезен.

Поэтому при использовании этих методов в библиотеках и фреймворках добавляется дополнительная "обертка для обработчика", устанавливающая правильный this.
Как эта обертка делается? что-то вроде того: el.attachEvent('event', function(e) { f1(e, el); }); ?
Ответить с цитированием
  #8 (permalink)  
Старый 07.03.2009, 20:35
Отправить личное сообщение для Андрей Параничев Посмотреть профиль Найти все сообщения от Андрей Параничев
 
Регистрация: 21.02.2008
Сообщений: 1,250

Сообщение от no.
Как эта обертка делается?
Я использую такую обертку:
/**
 * Объявляем и сразу вызываем функции,
 * чтоб не проверять поддержку методов
 * каждый раз:
 */
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 с фиксом "прозрачно".

Последний раз редактировалось Андрей Параничев, 07.03.2009 в 21:34.
Ответить с цитированием
  #9 (permalink)  
Старый 08.03.2009, 04:55
no. no. вне форума
Новичок на форуме
Отправить личное сообщение для no. Посмотреть профиль Найти все сообщения от no.
 
Регистрация: 16.08.2008
Сообщений: 9

Всем спасибо вроде разобрался с проблемой.
Для оперы просто изменил проверку на srcElement и поставил его на второе место, а на первое место currentTarget, который у последней оперы есть (давно ли?). А вот для IE пришлось делать обертку по типу того что я писал и Андрей Параничев, и вставлять в функцию оригинальный элемент вызова функции, т.е. TD + помогла статья с замыканиями.
Тему вроде можно закрывать.
Ответить с цитированием
Ответ


Опции темы Искать в теме
Искать в теме:

Расширенный поиск