Przejdź


Bug w attachEvent

14 Kwi 2008 @ 02:02:50 groszek 13 komentarzy

Męczyłem się z tym już ze dwa tygodnie – ot, kolejna durnota obecna w kochanym Internet Explorer. Jak zapewne każdy wie, przeglądarka ta nie posiada funkcji addEventListener, przez co trzeba używać attachEvent. No i nic, wystarczy prosta funkcja która wykrywa obecność jednej z tych funkcji i ją wywołuje.

Jeśli w funkcji wywołanej przez tradycyjny addEventListener znajdzie się słowo kluczowe this, będzie ono oznaczało „element html wywołujący zdarzenie”. Natomiast w wypadku attachEvent, zawsze oznacza to po prostu „window”. I o kant pupeczki można sobie to rozbić, bo odpada wygodne tworzenie części skryptów – nie można się posłużyć this odwołującym się np. do buttona; trzeba buttonowi przypisać identyfikator i jechać po getElementsById. Faaajnie.

Po żmudnych bojach znalazłem rozwiązanie. Olać głupi attachEvent:

 
        addEvent = function (obj, event, func) {
            if (obj.addEventListener)
                obj.addEventListener(event, func, false);
            else 
                obj["on"+event]=func;
        }
 

Oto prawdziwie przenośna funkcja. Nie używa attachEvent ale przynajmniej działa na każdej przeglądarce w ten sam sposób, czyli dobrze.

A więc jutro będzie czas na lekką modernizację tego bloga :-) a właściwie jego menu.
A oto przykład


Komentarze:

14 Kwi 2008 @ 08:11:20 guest123

Użyj lepiej tej funkcji: http://www.quirksmode.org/blog/archives/2005/10/_and_the_winner_1.html
;)

14 Kwi 2008 @ 10:32:05 puppy

Ta funkcja jest dziwna, przypisuje do elementu DOM atrybut w stylu "eclickfunction something() { alert('lol'); }" ... ?
Moje działa i ma się dobrze ;-) wystarczy przypisać "on[nazwa]" = "funkcja(){...}". Tak też robi mój przykładowy skrypt, umożliwiając tym samym działanie ładnie napisanego menu rozwijalnego [patrz przykład] również pod IE.

14 Kwi 2008 @ 10:38:13 Bigismall

Używaj MooTools, albo innej biblioteki do JS, nie będziesz musiał walczyć z takimi dziwactwami

14 Kwi 2008 @ 10:39:04 puppy

To by było trochę dziwne, używać biblioteki JS przy pisaniu własnej biblioteki JS :P

14 Kwi 2008 @ 19:11:19 blue

To może jeszcze powiesz po co Ci addEventListener? Bo właśnie zgubiłeś jedyny sens korzystania z niego.

14 Kwi 2008 @ 20:02:08 puppy

A więc stosowanie addEventListener w parze z attachEvent, który ma w/w buga jest dobre, natomiast stosując inną metodę zamiast attachEvent - już nie?

14 Kwi 2008 @ 20:42:44 coldpeer

"http://ejohn.org/projects/flexible-javascript-events/":http://ejohn.org/projects/flexible-javascript-events/

14 Kwi 2008 @ 22:27:25 blue

@puppy, a potrafisz powiedzieć dlaczego w ogóle korzystasz z addEventListener, jeżeli onclick (i wszystkie pochodne) doskonale działa w każdej przeglądarce od dawien dawna?
Z tego co wiem, to jedyną praktyczną zaletą porzucenia starego sposobu podpinania zdarzeń (onXXX = ''), jest możliwość podpięcia funkcji w ilości większej niż jedna. Jeżeli dopuszczasz możliwość użycia onclick, to znaczy, że Twoja funkcja będzie nadpisywana w IE przy kolejnych wywołaniach 'addEvent'. Wobec tego traci sens używanie addEventListener.

14 Kwi 2008 @ 22:30:44 puppy

Przypisywanie obiektom onXXX następuje wyłącznie w IE*; inne przeglądarki użyją "dobrej" metody addEventListener.
Oczywiście nadal można używać attachEvent, jeśli komuś nie przeszkadza dziwne zachowanie THIS.

* pewnie jeszcze jakieś stare, mało używane przeglądarki też.

15 Kwi 2008 @ 17:01:59 blue

Tak, wiem o tym - to przecież jest w kodzie. Chodzi mi o to, że nie możesz korzystać z zalet(y) addEventListener, jeżeli nadal 50% potencjalnych odwiedzających zostanie potraktowanych starą metodą, która nie daje tych możliwości. Równie dobrze możesz wszystkim bez wyjątku serwować onXXX i profity będziesz miał te same. Jak już wcześniej wspomniano (i podlinkowano), są na problem 'this' lepsze rozwiązania.

18 Kwi 2008 @ 17:23:46 Dominik Porda

Problem w tym, że


bc. addEvent(element, 'onclick', func1);
addEvent(element, 'onclick', func2);


w IE odpali tylko @func2()@. Mam inną propozycję Twojej funkcji:


bq. addEvent = function (obj, event, func) {
if ( obj.addEventListener ) obj.addEventListener(event, func, false);
else {
var oldEvent = obj["on"+event];
if ( typeof obj["on"+event] == 'function' ) obj["on"+event] = function() {
oldEvent();
func();
}
else obj["on"+event] = func;
}
}


:)

W sumie można byłoby nawet @obj.addEventListener@ wywalić, tylko użyć tego co siedzi w @else@.

18 Kwi 2008 @ 17:24:58 Dominik Porda

Fajnie, jakbyś włączył Textile. :)

21 Kwi 2009 @ 13:29:59 krzysiek

Witam,

dać sobie spokój z tym this…

fnHandler(e){
t=(e.srcElement)?e.srcElement:e.target;
// i już, albo dla kochających this
t=(e.srcElement)?e.srcElement:this;
.
.
}

i można używać attachEvent oraz addEventListener (fox, opera, IE).

pzdr :)

Pierdol licencje, kopiuj na zdrowie!