Почему я не мог добавить событие mousemove после mousedown в прототипе?

Я бы переместил свои прежние js-коды в более стильный ООП. Вот код.

function addEvent( obj, type, fn ) {
  if ( obj.attachEvent ) {
    obj['e'+type+fn] = fn;
    obj[type+fn] = function(){obj['e'+type+fn]( window.event );}
    obj.attachEvent( 'on'+type, obj[type+fn] );
  } else
    obj.addEventListener( type, fn, false );
}

function test() {

}

test.prototype = {
    init: function () {

        addEvent(document, 'mousedown', this.displaydown);

    },

    displaydown : function(e){
        document.getElementById('mydiv').innerHTML = "down";
        addEvent(document, 'mousemove', this.displaymove);
    },

    displaymove : function(e){
        document.getElementById('mydiv').innerHTML = "move";
    }
}

var test0 = new test();

test0.init()

Я не мог добавить событие mousemove после mousedown с помощью

addEvent(document, 'mousemove', this.displaymove);

Но если я напишу встроенный стиль, например

addEvent(document, 'mousemove', function(e){
   document.getElementById('mydiv').innerHTML = "move";
});

Ничего страшного. Похоже, что 2 кода делают одно и то же. Почему есть разница? Спасибо!


редактировать,

После борьбы в течение 2 ночей я наконец решил проблему. Спасибо johnvey за ваше просвещение.

Ошибка возникает в этом ключевом слове. В случае объекта это относится к окну, а не к самому объекту. Решение заключается в том, что я определил глобальный параметр me (me = this) в начале. Сейчас все хорошо.


person unigogo    schedule 05.05.2009    source источник


Ответы (1)


Это классический камень преткновения Javascript, связанный с тем, как ключ this находится внутри замыкания. Проиллюстрировать:

redPrinter = function() {
    this.X = 'red';
    return function() {
        return this.X;
    }
}

main = function() {
    this.X = 'blue';
    var myRedPrinter = new redPrinter();
    alert("Red printer returned: " + myRedPrinter());
}

main();

Этот код распечатает:

Red printer returned: blue

потому что область действия «этого» в строке:

return this.X

фактически привязан к объекту main() во время вызова.

Обычно есть два способа решить эту проблему:

1) Избегайте использования ключевого слова this в замыкании функции. Чтобы исправить ваш код таким образом, я бы просто собрал все привязки событий в одном месте, а не каскадировал их, тем самым удалив ссылки «это» как из «displaydown()», так и из «displaymove()»:

test.prototype = {
    init: function () {
        addEvent(document, 'mousedown', this.displaydown);
        addEvent(document, 'mousemove', this.displaymove);
    },

    displaydown : function(e){
        document.getElementById('mydiv').innerHTML = "down";
    },

    displaymove : function(e){
        document.getElementById('mydiv').innerHTML = "move";
    }
}

OR

2) Используйте каррирование функций для привязки области во время определения. Я поднял метод bind() из библиотеки Prototype, чтобы проиллюстрировать:

// declare the global bind() method for all functions
Function.prototype.bind = function(obj) {
    var method = this,
    temp = function() {
        return method.apply(obj, arguments);
    };
    return temp;
} 

test.prototype = {
    init: function () {
        addEvent(document, 'mousedown', this.displaydown);
    },

    displaydown : function(e){
        document.getElementById('mydiv').innerHTML = "down";

        // note that we bind the method object here
        addEvent(document, 'mousemove', this.displaymove.bind(this));
    },

    displaymove : function(e){
        document.getElementById('mydiv').innerHTML = "move";
    }
}

Важным изменением здесь является:

this.displaymove.bind(this)

который в основном говорит: «когда вы вызываете displaymove(), повторно переместите ключевое слово this в контекст исходной области вместо текущего объекта Event.

person johnvey    schedule 05.05.2009
comment
Привет, Джонви Спасибо! Думаю нужно делать как 2-й метод. Но я не мог связать(). На этом шаге возникает ошибка. Я использую IE.6. Это причина? - person unigogo; 05.05.2009
comment
IE6 не должен быть проблемой. Какую ошибку вы получаете? В качестве более широкого вопроса, что вы пытаетесь сделать? Вызов addEvent() из другого обработчика событий не очень хорош, потому что в конечном итоге вы будете подключать один и тот же обработчик снова и снова. - person johnvey; 05.05.2009
comment
johnvey, наконец-то я нашел ошибку в твоем коде. addEvent(документ, 'mousedown', this.displaydown); также должны быть связаны. или это в рамках mousedown есть окно. Я просто работал над слайдером для легкой загрузки. pagecolumn.com/webparts/sliders.htm - person unigogo; 11.05.2009