Как ссылаться на объект вызывающего абонента ("this") с помощью attachEvent

Используя метод .attachEvent() в IE, как я могу ссылаться на объект вызывающего объекта (элемент, вызвавший событие) с помощью this? В обычных браузерах, используя .addEventListener, var this указывает на элемент, тогда как в IE он указывает на объект window.

Мне нужно, чтобы он работал со следующим кодом:

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"
   }
}

Я только что сделал этот код, это не совсем то же самое, что и мой код, но если он сработает с ним, он работает со мной!

Ответы

Ответ 1

Из эта статья об атрибутах quirksmode в отношении attachEvent:

  • События всегда пузырятся, нет возможности захвата.
  • Функция обработки событий ссылается, а не копируется, , поэтому это ключевое слово всегда ссылается на окно и абсолютно бесполезно.

Результатом этих двух недостатков является то, что когда событие пузырится, невозможно знать, какой элемент HTML в данный момент обрабатывает событие. Я более подробно объясню эту проблему на странице заказа события.

Так как модель добавления событий Microsoft поддерживается только с помощью проводника 5 и выше в Windows, ее нельзя использовать для кросс-браузерных скриптов. Но даже для приложений Explorer-on-Windows лучше всего не использовать его, так как проблема пузырирования может быть довольно неприятной в сложных приложениях.

Я не тестировал его, но возможное обходное решение может заключаться в том, чтобы обернуть обработчик анонимной функцией, которая вызывает ваш обработчик через funct.call().

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

Приношу свои извинения за непроверенное решение. Мне не нравится это делать, но сейчас я не могу легко добраться до IE.

Ответ 2

Если вы находитесь в IE, вы можете получить объект "вызывающего", как вы его называете, путем доступа к window.event.srcElement в функции обработчика событий. Этот объект обычно упоминается как цель или источник события.

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

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

    // Do stuff
};

Этот код не проверен, но должен отключить его в правильном направлении.

Ответ 3

Привяжите его. Ну, вы не можете использовать Function.prototype.bind, который добавляется в javascript 1.8.5, но вы можете использовать закрытие и 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);
     });
   }
}

Ответ 4

Я думаю, было бы лучше расширить Element объект через цепочку прототипов вместо добавления вашего метода к каждому элементу, который вы хотите добавить события (работает со всеми браузерами)..

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"
   }
};

Таким образом, он будет работать для всех ваших текущих и будущих элементов (и вам нужно только запустить его один раз).