Слушатель событий, кажется, исчезает, когда я использую тот же код, чтобы добавить слушателя к другому элементу - PullRequest
0 голосов
/ 06 ноября 2011

Итак, это довольно долго меня беспокоило.

У меня есть конструктор javascript, который выглядит примерно так:

function TimeBlock(c, local_count){
    /* creates a timeblock */
    .
    .
    .
    _getel(this.id).addEventListener('mouseover', this.displayPopup)
    _getel(this.id).addEventListener('mouseout', this.killPopup)
}

, и в основном он создает объект TimeBlock и назначаетк нему те два обработчика событий, которые определены в TimeBlock.prototype следующим образом:

TimeBlock.prototype = {
    .
    .
    .
    block = getTimeBlock(e.target.id)
    //do something
    },

    killPopup: function(e){
    // //do something else
    }
}

И это работает.Я звоню new Timeblock (some_parameters) и получаю свой таймблок, он создает элемент в html (это div) и назначает ему слушателя.Я проверяю это, и он отлично работает.Но как только я снова его вызываю, я создаю новый элемент TimeBlock с работающими слушателями, но предыдущий перестает работать.Это все равно, что назначение этих слушателей на новый элемент отменяет слушателей, которые должны быть на предыдущем элементе.

Что еще более странно, что я назначил этих слушателей вручную через консоль javascript, и там все работало нормально.Я использую Firefox 7.0.1 и Firebug для этих тестов.

Большое спасибо

1 Ответ

0 голосов
/ 06 ноября 2011

Подозрительно этот код:

_getel(this.id).addEventListener('mouseover', this.displayPopup)

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

Существуют различные способы гарантировать, что ваши функции вызываются с правильным значением this, один из которых выглядит следующим образом:

function TimeBlock(c, local_count){
    /* creates a timeblock */
    .
    .
    .
    var self = this;
    _getel(this.id).addEventListener('mouseover', function(event) {
        self.displayPopup(event);
    });
    _getel(this.id).addEventListener('mouseout', function(event) {
        self.killPopup(event);
    });
}

Больше чтения:

Единственное, что приходит на ум, это то, что mouseover и mouseout пузырь для родительских элементов, что может сбить с толку, если вы не будете осторожны. Так, например, если у вас есть:

<div>Foo <span>bar</span></div>

... и вы наблюдаете за mouseover и mouseout на div, вы увидите mouseout, когда мышь переместится из span ("бар") в div ( "foo"), что может быть удивительно, если вы этого не ожидаете.


Вот пример, демонстрирующий два независимых экземпляра, подключенных к независимым элементам, как указано выше ( live copy ):

window.onload = function() {

    new TimeBlock("firstElement");
    new TimeBlock("secondElement");

    function _getel(id) {
      return document.getElementById(id);
    }

    function TimeBlock(id){
        var self = this;
        this.id = id;
        this.counter = 0;
        _getel(this.id).addEventListener('mouseover', function(event) {
            self.displayPopup(event, this);
        });
        _getel(this.id).addEventListener('mouseout', function(event) {
            self.killPopup(event, this);
        });
    }

    TimeBlock.prototype.displayPopup = function(event, element) {
        ++this.counter;
        element.innerHTML = "Display, counter = " + this.counter;
    };

    TimeBlock.prototype.killPopup = function(event, element) {
        element.innerHTML = "Remove, counter = " + this.counter;
    };

};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...