2015-11-10 4 views
2

This jsfiddle демонстрирует базовый макет того, чего я пытаюсь достичь. После нажатия ссылки я должен навести курсор на элементы списка, и текст должен появиться на странице, но они этого не делают. Когда я печатаю значения строк, которые должны появляться, они «неопределены». Почему это так?Получение значения при наведении «undefined»

Вот js ниже, но я рекомендую посмотреть на скрипку.

$('#link1').click(function() { 
    var foolist = ["foo1", "foo2", "foo3"]; 

    for (var i = 0; i < foolist.length; i++) { 
     var li = document.createElement('li'); 
     li.innerHTML = "This is a link."; 
     $(li).hover(function() { 
      console.log(foolist[i]); 
      $('#p1').append(foolist[i]); 
     }, 
     function() {}); 
     $('#ul1').append(li); 
    } 
}); 
+0

Добро пожаловать на закрытие! Пожалуйста, прочтите это сначала http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example –

ответ

2

Вы обнаружили необходимость в том, что называется закрытием! Поздравляем - не многие люди видят, насколько они классные. Это pulled from a great MSDN article - Я очень рекомендую прочитать остальную часть.

Проблема в том, что переменная i больше не имеет значения, которое она сделала, когда вы позвонили .hover - если вы ее занесете, вы увидите, что i===3. Почему это так? Функция, которую вы передаете в .hover, является замыканием, что означает, что она состоит из самой функции и своего рода «моментального снимка» области действия .click. Вы создаете закрытие с каждой итерацией цикла, но все они имеют один и тот же «моментальный снимок». Когда вы попытаетесь получить доступ к i через событие click, цикл уже завершен.

Итак, как вы можете это решить? Больше замыканий!

function showText(i) { 
    $('#p1').append(foolist[i]); 
} 

function makeTextCallback(i) { 
    return function() { 
     showText(i); 
    }; 
} 

for (var i = 0; i < foolist.length; i++) { 
    $(li).hover(makeTextCallback.call(this,i)); 
} 

Это называется «фабрикой функций». Вы отправляете i в makeTextCallback, который фиксирует i в закрытии, который он возвращает.

https://jsfiddle.net/aLofhaxp/28/

+0

Спасибо. Я теперь лучше понимаю концепцию. Но я пересмотрел как таковой, и он не сработал - что я делаю неправильно? https://jsfiddle.net/aLofhaxp/18/ –

+0

Эй, @ JoonPark Park, мои извинения - мой пример не был настроен совершенно правильно. Я обновил свой ответ и связался с новым jsfiddle. – Harangue

+0

Работает как шарм. Огромное спасибо. –

1

простое правило, чтобы избежать каких-либо замыканий внутри циклов.

Еще один хороший способ, чтобы определить такие вещи data атрибуты:

$('#link1').click(function() { 
    var foolist = ["foo1", "foo2", "foo3"]; 

    foolist.forEach(function(x) { 
     $("<li/>") 
      .data('list', x) 
      .text("This is a link"); 
      .hover(fooListItemOnHover, fooListItemOnHoverOff) 
      .appendTo('#ul1'); 
    } 
}); 

function fooListItemOnHover() { 
    var data = $(this).data('list'); 
    console.log(data); 
    $('#p1').append(data); 
} 

function fooListItemOnHoverOff() { 
} 

Это будет производить элементы с дополнительным data-list атрибутом, который будет хранить ваши пользовательские данные:

<li data-list='foo1'>This it a link</li> 

Затем сценарий прочитает эти данные с помощью jQuery data().

0

Используйте .data() метод jQuery для присоединения данных любого типа к элементам DOM.

$('#link1').click(function() { 
 
    var foolist = ["foo1", "foo2", "foo3"]; 
 
    
 
    for (var i = 0; i < foolist.length; i++) { 
 
     var $li = $("<li/>"); 
 
     $li.data("VAL", foolist[i]); 
 
     $li.html("This is a link."); 
 
     $($li).hover(function() { 
 
      var value = $(this).data("VAL"); 
 
      console.log(value); 
 
      $('#p1').append(value); 
 
     }, 
 
     function() {}); 
 
     $('#ul1').append($li); 
 
    } 
 
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script> 
 
<a id="link1" href="javascript:;">Click to show list</a> 
 

 
<ul id="ul1"></ul> 
 
<p id="p1"></p>