Pytanie Jak odwołać się do obiektu wywołującego ("this") za pomocą metody attachEvent


Korzystanie z metody .attachEvent() w IE, jak mogę odwołać się do obiektu wywołującego (element, który wywołał zdarzenie) z this? W normalna przeglądarki, używając .addEventListener, var this wskazuje na element, podczas gdy w IE wskazuje na window obiekt.

Potrzebuję go do pracy z następującym kodem:

var element = //the element, doesn't matter how it is obtained
element.addAnEvent = function(name, funct){
   if(element.addEventListener) // Works in NORMAL browsers...
   else if(element.attachEvent){
     element.attachEvent("on"+name, funct);
     //where the value of "this" in funct should point to "element"
   }
}

Właśnie napisałem ten kod, nie jest dokładnie taki sam jak mój kod, ale jeśli to działa, to działa ze mną!


13
2018-01-04 02:15


pochodzenie




Odpowiedzi:


Od ten artykuł z quirksmode odnośnie do attachEvent:

  1. Wydarzenia zawsze się bańczą, nie ma możliwości przechwytywania.
  2. Funkcja obsługi zdarzeń jest przywoływana, a nie kopiowana, więc to słowo kluczowe zawsze odnosi się do okna i jest całkowicie bezużyteczne.

Rezultatem tych dwóch słabości jest to, że gdy bańka się pojawia, nie można stwierdzić, który element HTML aktualnie obsługuje wydarzenie. Wyjaśnię ten problem pełniej na stronie Zlecenie zdarzeń.

Ponieważ model dodawania zdarzeń Microsoft jest obsługiwany tylko przez program Explorer 5 i nowsze wersje w systemie Windows, nie można go używać w skryptach działających w różnych przeglądarkach. Ale nawet w przypadku aplikacji Explorer-on-Windows najlepiej go nie używać, ponieważ problem z bulgotaniem może być dość nieprzyjemny w złożonych aplikacjach.

Nie testowałem tego, ale możliwym obejściem może być owinięcie programu obsługi w anonimową funkcję, która wywołuje program obsługi za pośrednictwem funct.call().

else if(element.attachEvent){
   element.attachEvent("on"+name, function(){ funct.call( element ) });
}

Moje przeprosiny za nieprzetestowane rozwiązanie. Nie lubię tego robić, ale nie mogę teraz łatwo dostać się do IE.


16
2018-01-04 02:24



więc zamiast go używać, powinienem użyć klasycznego sposobu element.onevent=function? (Dawny. element.onmouseup...) - JCOC611
@ JCOC611: Właśnie zaktualizowałem moją odpowiedź. Moje potencjalne rozwiązanie kodu było wstecznie za pierwszym razem. Jeśli to nie zadziała, to tak, myślę, że klasyczny sposób byłby awarią. - user113716
Próbowałem już wcześniej, ale po prostu zorientowałem się, co zrobiłem źle. Wielkie dzięki! Patrick ftw !!! XD - JCOC611
@ JCOC611: Nie ma za co, ale jestem nieco zdezorientowany z powodu, dla którego to zrobiłeś addAnEvent funkcja dołączona bezpośrednio do element. Myślę, że bardziej użyteczne byłoby przekazanie elementu do oddzielnej funkcji jako trzeciego parametru. Ponieważ moje rozwiązanie odnosi się do elementzmienna, może zawieść. Jeśli nazywasz to jak element.addAnEvent( 'click', thefunc ), powinieneś zmienić powyższe rozwiązanie funct.call( this ). Mimo to rozważałbym inne podejście. - user113716
nie martw się, myślę, że wiem, co robię lol, używając "tego" w call metoda zamiast zmiennej była tym, co zrobiłem źle, ponieważ w IE "to" w anonimowej funkcji odwołuje się również do obiektu okna - JCOC611


Jeśli jesteś w IE, możesz uzyskać obiekt "dzwoniący", jak go nazywasz, uzyskując dostęp window.event.srcElement w ramach funkcji obsługi zdarzenia. Ten obiekt jest zwykle nazywany zdarzeniem cel lub źródło.

var funct = function(event) {
    if ( !event ) {
        event = window.event;
    }

    var callerElement = event.target || event.srcElement;

    // Do stuff
};

Ten kod jest nieprzetestowany, ale powinien Cię ustawić we właściwym kierunku.


10
2018-01-04 02:41



Praca wyjątkowo płynna. Dziękuję Ci. - dotTutorials


Zwiąż to. Cóż, nie możesz użyć Function.prototype.bind który zostanie dodany w javascript 1.8.5, ale możesz użyć zamknięcia i Function.prototype.apply.

var element = //the element, doesn't matter how it is obtained
element.addAnEvent = function(name, funct){
   if(element.addEventListener) // Works in NORMAL browsers...
     //...
   else if(element.attachEvent){
     element.attachEvent("on"+name, function() {
       //call funct with 'this' == 'element'
       return funct.apply(element, arguments);
     });
   }
}

0
2018-01-04 02:35



Och, jakże tęskniłem za tym, że Patric na to odpowiedział. - Hemlock


Myślę, że lepiej byłoby przedłużyć Element obiekt , przez prototypowy łańcuch, zamiast dodawać swoją metodę do każdego elementu, do którego chcesz dodać zdarzenia (działa ze wszystkimi przeglądarkami) ..

Element.prototype.addAnEvent = function(name, funct){
   if(this.addEventListener) // Works in NORMAL browsers...
   {
     this.addEventListener(name,funct, false);
   }
   else if(this.attachEvent){
     var _this = this;
     this.attachEvent("on"+name, function(){funct.apply(_this);});
     //where the value of "this" in funct should point to "element"
   }
};

W ten sposób będzie działać dla wszystkich twoich obecnych i przyszłych elementów (i musisz uruchomić go tylko raz).


0
2018-01-04 03:02



Tak, wiem o prototypowaniu JS. Mimo to mój kod nie wymaga prototypowania. Robię odpowiednik jQuery $() funkcjonować. Poza tym założę się, że prototypowanie nie jest w pełni kompatybilne z różnymi przeglądarkami. - JCOC611
@ JCOC, powyższy kod jest testowany w IE, FF, Chrome, Safari i Operze .. Ale sugeruję tylko alternatywę. Znasz szczegóły i możesz zdecydować, co jest najlepsze dla Twojego przypadku :) - Gabriele Petrioli
To nie zadziała w IE 7 lub niższym. - Tim Down
@Tim, rzeczywiście .. IT jest dla IE8 +, i ogólnie rozszerzenie obiektu DOM poprzez łańcuch prototypów jest źle widziane - Gabriele Petrioli