Передача параметров на слушателей событий с циклами - PullRequest
8 голосов
/ 06 августа 2011

Просто быстрый вопрос, может кто-нибудь сказать мне, почему это не работает и как это исправить?По сути, он берет группу строк таблицы в HTML и динамически присоединяет к ним события щелчка.

for (var a=index; a<rows.length; a++) {
    tr = rows[a];
    tr.onclick = function() { DropDownManager.onItemClick(tr, a); };
    tr.observe("click", function() { DropDownManager.onItemClick(tr, a); });
}

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

Ответы [ 4 ]

14 голосов
/ 06 августа 2011

JavaScript не имеет области видимости блока, например, петли не создают новую область видимости. Вы можете создать его с помощью функции:

for (var a=index; a<rows.length; a++) {
   (function(a) {
      tr = rows[a];
      tr.onclick = function() { DropDownManager.onItemClick(this, a); };
      tr.observe("click", function() { DropDownManager.onItemClick(this, a); });
   }(a));
}

В зависимости от того, что такое rows и tr, вам может даже не понадобиться индекс цикла. Возможно, вы можете получить индекс элементов внутри обработчика событий другим способом. Например. если tr является HTMLTableRowElement [MDN] , то вы можете получить его позицию среди других строк с помощью this.rowIndex.

Btw. почему вы связываете один и тот же обработчик событий дважды?

4 голосов
/ 06 августа 2011

Помимо сохранения атрибутов объекта DOM в цикле, вы также можете использовать замыкания функций, чтобы «заморозить» копию переменных в цикле для конкретного вызова функции. Вы можете сделать это так:

for (var a=index; a<rows.length; a++) {
    tr = rows[a];
    tr.onclick = function(tr, a) {
        return(function() { 
            DropDownManager.onItemClick(tr, a); 
        });
    }(tr,a);
}

То, что это делает, говорит, что присваивает tr.onclick результаты выполнения анонимного вызова функции, который принимает две переменные в качестве параметров (названных tr и a) и передает текущие значения tr и a в качестве параметров (это передача Текущие значения «замораживают» текущие значения этих переменных в закрытии этой функции.

Результатом выполнения этого вызова функции является сама другая анонимная функция. Поскольку эта внутренняя анонимная функция теперь назначена tr.onclick, она создает замыкание функции, которое поддерживает все состояние, которое в данный момент находится в этом закрытии. Это состояние включает в себя «замороженные» значения tr и a, но они остаются внутренними только для этого закрытия функции, поэтому каждый раз в цикле создается новое закрытие функции с новыми «замороженными» и «сохраненными» значениями tr и a.

0 голосов
/ 06 августа 2011

Отчасти потому, что я педантичен, а отчасти потому, что это возможно, вот то же самое, что сделано просто.

Event.on('table_id', 'click', 'tr', function(event, tr) {
    DropDownManager.onItemClick(tr, rows.indexOf(tr));
});

Обратите внимание, что содержащая таблица необходима для всплывающих событий, она определяетсяID, но вы также можете передать элемент напрямую.

0 голосов
/ 06 августа 2011
for (var a=index; a<rows.length; a++) {
    tr = rows[a];
    tr.setAttribute('a', a);
    tr.onclick = function() { DropDownManager.onItemClick(this, this.getAttribute('a')); };
    tr.observe("click", function() { DropDownManager.onItemClick(this, this.getAttribute('a')); });
}

попробуйте этот способ.

Он пройдет tr, потому что переменная tr установлена ​​как последняя строка.

...