2011-06-19 34 views
3

帶狀態按鈕的交互式地圖,每個按鈕的狀態縮寫都是一個id,當點擊一個按鈕/狀態時我想啓動函數「stateSelect」併發送狀態縮寫所以我知道什麼被按下了。爲什麼以下不工作?Javascript Array addEventListener

var stateList = new Array("AK","AL","AR","AS","AZ","CA","CO","CT","DC","DE","FL","GA","GU","HI","IA","ID", 
    "IL","IN","KS","KY","LA","MA","MD","ME","MH","MI","MN","MO","MS","MT","NC","ND","NE","NH","NJ","NM","NV","NY", 
    "OH","OK","OR","PA","PR","PW","RI","SC","SD","TN","TX","UT","VA","VI","VT","WA","WI","WV","WY"); 

    for (var i = 0; i < stateList.length; i++) { 
     document.getElementById(stateList[i]).addEventListener('mousedown', function() {stateSelect(stateList[i])}, false); 
    } 

我明顯想避免50行代碼,但我不知道爲什麼這個簡單的循環不工作。

回答

5

因爲處理程序運行時,它會查找i的值,該值是循環完成後的任何位置。

您需要範圍i變量的函數:

function listenerForI(i) { 
    document.getElementById(stateList[i]).addEventListener('mousedown', function() {stateSelect(stateList[i])}, false); 
} 
for (var i = 0; i < stateList.length; i++) { 
    listenerForI(i); 
} 

現在由處理器引用的i將是參數被調用的listenerForI功能。因此,i將引用從for循環傳入的值。

+0

我試過上面的代碼,現在只有阿拉斯加(AK)是可點擊的。 – Stephen

+0

@Stephen:適合我。 [下面是一個例子。](http://jsfiddle.net/8fbqy/) – user113716

+0

明白了,我以爲我已經創建了divs來操縱,但是第一個塊做了這個把戲。非常感謝。 – Stephen

1

您有確定範圍的問題。 Javascript不是塊範圍的;它是功能範圍的。基本上,當你想在循環中創建一個新變量時,你必須創建一個新函數必須

最優雅的方式來做到這一點如下:

stateList.map(function(abbrev){ 
    $(abbrev).mousedown(function(){stateSelect(abbrev)}); 
}); 

如果你不使用jQuery,僅僅用document.getElementById(abbrev).addEventListener取代$(abbrev).mousedown。 (只是爲了搶佔那些「地圖不符合標準」的人;它是在javascript ECMA-262標準第5版中得到了所有瀏覽器供應商的支持。如果有人對支持舊版瀏覽器持偏執態度,只是$.map。)

下面是如何使用for循環這樣做;這是一個有點難看,但它演示了通過函數創建新關閉的必要性:就像我說的,不是必要的醜陋有點

for(var i=0; i<stateList.length; i++) 
    (function(i){ 
     $(stateList[i]).mousedown(...); 
    })(i); 

;你也可以這樣做,這是稍微不難看,但基本上是相同的東西:

function createListener(abbrev) { 
    $(abbrev).mousedown(...); 
} 
for(var i=0; i<stateList.length; i++) 
    createListener(stateList[i]); 
+0

*「如果有人偏執支持舊版瀏覽器......」*這不是偏執狂。 IE6-8不支持'Array.prototype.map',這代表了一個巨大的基礎。 – user113716