2011-05-29 19 views
3

我想在jQuery中動態地創建一個項目列表,並動態地將一個點擊處理程序綁定到每個處理程序,並且在創建點擊處理程序的同時範圍內的變量。在創建時綁定範圍變量的點擊處理程序?

下面的代碼創建1-6項的列表,但單擊處理似乎只與最後一個項目的值綁定 - 警報總是顯示6.

這是一個JavaScript範圍的問題嗎?如何將警報與1-6的變量綁定?

HTML:

<ul id="saved-list"> 
</ul> 

JS:

var all_cookies = [1,2,3,4,5,6]; 
for (var i = 0; i < all_cookies.length; i++) { 
    var route_num = all_cookies[i]; 
    var list_item = "<li><a href='#saved-route'>"; 
    list_item += "<p>" + route_num + "</p></a></li>"; 
    var newLi = $(list_item); 
    newLi.bind('click', function(){ 
     alert(route_num); 
    }); 
    $('#saved-list').append(newLi);  
} 

見的jsfiddle這裏:http://jsfiddle.net/n6FU5/

回答

5

這是「範圍」和「大括號」之間的經典的JavaScript混淆。事實證明,大括號與JavaScript中的範圍無關。範圍僅從函數產生。

這樣做的一個結果是變量總是被提升到範圍的頂部,即最近的函數。所以,你的代碼是完全等同於:

var all_cookies = [1,2,3,4,5,6]; 
var i; 
var route_num; 
var list_item; 
var newLi; 

for (i = 0; i < all_cookies.length; i++) { 
    route_num = all_cookies[i]; 
    list_item = "<li><a href='#saved-route'>"; 
    list_item += "<p>" + route_num + "</p></a></li>"; 
    newLi = $(list_item); 
    newLi.bind('click', function(){ 
     alert(route_num); 
    }); 
    $('#saved-list').append(newLi);  
} 

考慮到這一點,你可以看到,因爲route_num是同一個變量通過循環每一次,以後的循環結束它的值設置爲6和在將來每當點擊處理程序被調用時,6就是你所看到的。解決這個問題

一種方法是來包裝循環的內容在自執行匿名函數:

var all_cookies = [1,2,3,4,5,6]; 
for (var i = 0; i < all_cookies.length; i++) { 
    (function() { 
     var route_num = all_cookies[i]; 
     var list_item = "<li><a href='#saved-route'>"; 
     list_item += "<p>" + route_num + "</p></a></li>"; 
     var newLi = $(list_item); 
     newLi.bind('click', function(){ 
      alert(route_num); 
     }); 
     $('#saved-list').append(newLi);  
    }()); 
} 

這樣,當變量得到升起,他們只是得到提升到頂部那個內部的自我執行函數,所以每個循環中都會有不同的實例。

+0

Ooooo。喜歡:)。我想出了這個解決方案:http://jsfiddle.net/n6FU5/2/,雖然不是很漂亮,但它有一個有趣的功能xD – Alxandr 2011-05-29 17:56:35

+0

天才 - 謝謝。太好了! – phil123 2011-05-29 18:13:50

+0

+1,很好的解決方案,但如果我不得不調試某人充滿像這樣的小提琴的代碼,我不會太高興。嵌套其中的一些,這是混淆你的代碼給你的合作開發者一些噩夢的有效方法。 :) – DarthJDG 2011-05-29 20:00:38

1

這就是因爲JavaScript的工作方式。發現範圍內的變量是可訪問的,但它們不是每個子範圍的單獨實例。因此,在處理函數被調用時,你的變量的值是6。

解決方法是將route_num保存在數據屬性中,並在您的點擊處理程序中檢索它。

var all_cookies = [1, 2, 3, 4, 5, 6]; 

for (var i = 0; i < all_cookies.length; i++) { 
    var route_num = all_cookies[i]; 
    var list_item = "<li><a href='#saved-route'>"; 
    list_item += "<p>" + route_num + "</p></a></li>"; 

    var newLi = $(list_item); 
    newLi.data('routenum', route_num); 
    newLi.bind('click', function() { 
     alert($(this).data('routenum')); 
    }); 

    $('#saved-list').append(newLi); 
} 

這是你的固定提琴:http://jsfiddle.net/n6FU5/1/

+1

難道你不能神奇地做一些事情來欺騙範圍?使用數據是一個無聊的解決方案,需要以純粹的方式解決這個問題,對吧? – Alxandr 2011-05-29 17:50:27

+0

是的,這是解決問題的一種非常強硬的方式,涉及操作DOM元素等。 – Domenic 2011-05-29 17:55:22

+1

哈哈:http://jsfiddle.net/n6FU5/2/ – Alxandr 2011-05-29 17:55:45

2

您遇到的問題是您的onclick函數在單擊鏈接時返回變量route_num的值。 route_num是一個全局變量,當循環結束運行時,值保留爲6。所以你需要做的是設置函數來在for循環運行時提醒route_num的值。

要做到這一點的方法是將函數構造爲字符串,以便您可以將字符串的值附加到函數定義。這裏是我想要做的認爲的一個例子。

var all_cookies = [1,2,3,4,5,6]; 
for (var i = 0; i < all_cookies.length; i++) { 
    var route_num = all_cookies[i]; 

    var list_item = "<li><a href='#saved-route'>"; 
    list_item += "<p>" + route_num + "</p></a></li>"; 
    var newLi = $(list_item); 

    var fn = new Function("alert('" + route_num + "');"); 
    newLi.bind('click', fn); 

    $('#saved-list').append(newLi);  
} 
相關問題