2013-06-13 2 views
2

я использую эту строку кода, чтобы добавить прослушиватель событий в моей Div-х, которые создаются с помощью forloop:Назначение EventListener в цикле

for(var i in mail){ 
    //create div 
    parent.addEventListener("click",function(){read_msg(mail[i].id);},false); 
    //append to parent 
} 

Это вызывает проблему mail[i].id быть последним идентификатор для всех их. Я прочитал несколько примеров того, как его решить, но я считаю, что это все еще очень запутанно.

мне предложили решение:

(function(){read_msg(mail[this].id)}).bind(i); 

Но я сказал это не большое решение, чтобы использовать, надеялся, кто-то может объяснить, как вы получите read_msg держать правильное значение id? Это всегда кажется немного беспорядочным с точки зрения решения.

+0

«Но я сказал, что это не большое решение использовать» --- какие-либо подробности? «Не очень» не является отличным объяснением. – zerkms

+0

Это решение в порядке. – elclanrs

+0

@zerkms - это вопрос, почему решение не подходит? Мне больше ничего не сказали. – Sir

ответ

1

Это потому, что вы используете переменную замыкания i в функции обработчика события.

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

В родительской области значение продолжает изменять значение i по мере выполнения цикла, поэтому весь обратный вызов имеет то же значение для i.

Решение здесь состоит в создании локальной закрытости

for(var i in mail){ 
    (function(myvar){ 
     parent.addEventListener("click",function(){read_msg(mail[myvar].id);},false); 
     //append to parent 
    })(i); 
} 

Вот что мы делаем мы имеем сразу запущенную функцию Expression, к которому мы передаем значение i в качестве параметра myvar. Поэтому каждая итерация в цикле создаст независимое закрытие.

+0

Итак, какое правильное решение или, может быть, это не правильный термин, а решение, которое обычно считается лучшей практикой? – Sir

+0

Делегирование событий лучше. Поищи это. В основном вы просматриваете событие click на контейнере со всеми элементами в этой почтовой коллекции. События пузырьков для их родителей (если вы их не остановите), но вы все равно можете получить целевой элемент с объектом события. Это также удобно для элементов, которые добавляются после установки события. Там есть кроссбраузер с хиджинсом, т. Е. <9. –

+0

@Dave Это вариант. Я не думаю, что использование '.bind()' для установки значения 'this' является правильным, потому что обычно с обработчиками событий значение' this' устанавливается как элемент ... Я знаю, что вы просто вызываете ' read_msg' и передачи определенного элемента в соответствии с циклом, но в качестве общего решения вы должны использовать что-то *, как * этот ответ. Этот ответ, очевидно, выполняет свою работу, но я нахожу это беспорядочным. Вы можете легко создать новую функцию, которая «генерирует» функцию, которая захватывает это значение из цикла – Ian

1

вы можете использовать методы объектов + массивов в большинстве браузеров в сторону шага объема надоедливого цикла «ошибка» в JS:

function addClick(key){ 
    //create div 
    parent.addEventListener("click",function(){read_msg(mail[key].id);},false); 
    //append to parent 
} 

Object.keys(mail).forEach(addClick); 

поскольку функции имеют объем и Foreach съедает функцию, вам не нужен extra anon wrapper, когда вы используете методы Array.

если вы хотите идти на все новые JS жаркость:

function addClick(key){ 

    parent.addEventListener("click", this.method.bind(this.elm, this.source[key].id), false); 

} 

Object.keys(mail).forEach(addClick, {elm:parent, source: mail, method:read_msg }); 

где вы меняете исходный объект ключа, чтобы разрешить использование других, чем «почта» объекты, элементы, кроме «родителя» пристроить события а также методы, отличные от «read_msg», без необходимости касаться логики или использовать слово «return» ... В принципе, независимо от того, что вы настраиваете в традиционном инициализаторе цикла C-стиля, вы переходите к this.something и повторите применение логики по мере необходимости.

0

Поскольку каждая анонимная функция, которую вы определяете как обработчик события с каждой итерацией цикла, будет обладать той же областью, что и все остальные, все они будут ссылаться на тот же var (i), что и адрес массива для сообщения, которое вы пытаетесь отобразить , Поскольку вы переопределяете var i с каждым циклом, вы всегда увидите последнее сообщение в вашем массиве сообщений, отображаемое в каждом событии клика, потому что последнее значение, присвоенное i, будет длиной вашего массива «mail».

Вот как это исправить:

var helper = function(index) { 
    parent.addEventListener("click", function(){read_msg(mail[index].id);},false); 
} 

for(var i in mail) { 
    helper(i); 
} 
Смежные вопросы