связывающие обработчики событий в прототипе и сохраняющие ссылку на элемент - PullRequest
1 голос
/ 11 ноября 2009

Я хочу иметь возможность использовать обработчик связанных событий в прототипе и сохранить мой контекст "this". Но это, похоже, разрушает удобную привязку по умолчанию, которую прототип предоставляет обработчикам событий.

Из документов:

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

Это именно то, что я хочу. Как только я свяжу функцию с моим собственным контекстом, могу ли я каким-либо образом получить доступ к этому «наблюдаемому элементу»? Я не могу рассчитывать, что e.element () даст мне наблюдаемый элемент (это может быть дочерний элемент):

initialize: function() {
     Event.observe('foo', 'click', this.addItem.bind(this));
},

...

addItem: function(e) {
   e.element() // -> clicked element, not necessarily observed element
}

Я знаю, что есть bindAsEventListener, но здесь это не нужно, и я не вижу, как я могу получить доступ к целевому элементу, когда функция связана.

Я также знаю, что есть e.currentTarget, но в IE это не работает, не так ли?

Ответы [ 2 ]

2 голосов
/ 12 ноября 2009

Когда вы используете .bind, ваша ссылка на наблюдаемый элемент через this перезаписывается. Если у вас есть следующая разметка:

<div id="foo">
    I am the Foo
    <button id="bar">I am the Bar</button>
</div>

Без использования .bind вы можете получить доступ к наблюдаемым и стреляющим элементам следующим образом:

function greenEggsAndHam (evt) {
    console.log('Observed Element: %o', this);
    console.log('Clicked Element: %o', $(evt.element()));
}
Event.observe('foo', 'click', greenEggsAndHam);

Однако, если вы хотите использовать метод класса в качестве обработчика событий и, следовательно, должны использовать .bind, тогда решение состоит в том, чтобы включить идентификатор наблюдаемого элемента в качестве одного из аргументов обработчику событий при первом связывании событие, вот так:

var Test = Class.create({
    initialize: function() {
        Event.observe('foo', 'click', this.greenEggsAndHam.bind(this, 'foo'));
    },
    greenEggsAndHam: function (el, evt) {
        console.log('Observed Element: %o', $(el));
        console.log('Clicked Element: %o', $(evt.element()));
        console.log('Class reference: %o', this);
    }
});
var T = new Test();

Тем не менее, для согласованности я бы предложил вам использовать .bindAsEventListener вместо .bind и изменить обработчик событий на function (evt, el) {, чтобы объект события был первым аргументом, а наблюдаемый элемент - вторым.

0 голосов
/ 12 ноября 2009

У меня тоже недавно была эта проблема. Мой ответ заключался в том, чтобы обернуть функцию в другую функцию, которая выполняет ту работу, которая вам нужна. Возможно, я испортил порядок, но curry добавит this к аргументам анонимной функции, а затем вы переупорядочите оттуда.

initialize: function() {
  Event.observe('foo', 'click', 
    function(e,that) { that.addItem(e,this); }.curry(this)
    );
  },
addItem: function(evt, evtElm) {
  ...
  }
...