-1

我有幾個pieChart對象存儲在shapes數組中...我想爲每個對象添加事件偵聽器。我試圖做這樣的:循環內的EventListeners [JavaScript]

var tempS = shapes.slice(); 

for(var i=0; i<shapes.length; i++) 
{ 
    var S = tempS.pop(); 
    if(S.name == 'pieChart') 
    { 
     document.getElementById(S.id).addEventListener('mousedown', function(e){ 
      alert(S.id); 
    }, false); 
} 

}

這裏的問題是,即使當我點擊pieChart2(ID-> 2),它總是給ID-> 1(因爲它最後彈出)。請解釋這種行爲,以及可能是這種做法的有效方式。

回答

0

考慮到var聲明具有的功能範圍(或全球性的,如果在全球範圍內聲明的),你的代碼是相當於:

var tempS = shapes.slice(), 
    i, S; 

for (i = 0; i < shapes.length; i++) { 
    S = tempS.pop(); 
    if (S.name == 'pieChart') { 
     document.getElementById(S.id).addEventListener('mousedown', function (e) { 
      alert(S.id); 
     }, false); 
    } 
} 

現在很明顯S的範圍在for塊之外,並且由於事件處理程序將在循環完成後觸發,所以S將具有最後一次迭代的值。

您需要通過回調工廠(如此related answer)或IIFE來創建新範圍,以捕獲迭代的當前值S

var tempS = shapes.slice(); 

for (var i = 0; i < shapes.length; i++) { (function() {//introduces a new scope 
    var S = tempS.pop(); //now S is scoped inside this iteration's IIFE 
    if (S.name == 'pieChart') { 
     document.getElementById(S.id).addEventListener('mousedown', function (e) { 
      alert(S.id); //will reference the IIFE scope's S 
     }, false); 
    } 
}()); } 

您可以在許多替代的方式做到這一點爲好,例如,使用Array#forEach

var tempS = shapes.slice(); 
shapes.forEach(function(S) { //S is now scoped in the forEach callback scope 
    if (S.name == 'pieChart') { 
     document.getElementById(S.id).addEventListener('mousedown', function (e) { 
      alert(S.id); 
     }, false); 
    } 
}); 

注意,這將改變迭代順序,但我相信它不會爲這件事用例。


在ES6將有可能使用let創建塊作用域的變量:

for (var i = 0; i < shapes.length; i++) { 
    let S = tempS.pop(); //scoped inside the `for` block 
    if (S.name == 'pieChart') { 
     document.getElementById(S.id).addEventListener('mousedown', function (e) { 
      alert(S.id); 
     }, false); 
    } 
} 

我在這裏留下這種方法對於未來的讀者,爲let尚未準備好生產呢。儘管最近的瀏覽器確實有實驗性實現(請參閱ES6 compat table)。

0

您可以使用

e.target.id 

代替

S.id 

在事件監聽器

+0

你的意思是document.getElementById(e.target.id).addEventListener(....... ??:S –

+0

我的意思是alert(e.target.id) –

+0

這不會影響代碼的工作!警報只是顯示值... –

1

here

使用underscore.js:

_.each(shapes, function(s) { 
    if(s.name === 'pieChart') { 
     document.getElementById(s.id).addEventListener('mousedown',function(e) { 
      e = e || window.event; 
      var target = e.target || e.srcElement; 
      alert(target.id); 
     }); 
    } 
}); 

來解釋你的代碼的行爲,你要記住,JavaScript使用功能範圍,而不是封鎖範圍。因此,由於您的定義S在eventListener回調函數之外,回調中的S對引用的引用將是S的當前值,循環執行後這些值將是shapes數組中的最後一個pieChart對象。

1

在回調函數中,使用this而不是再次訪問id