2017-05-30 118 views
1

我需要向8個對象(手掌)添加一些偵聽器。 這些對象是相同的,但行爲必須根據其位置進行更改。 我有如下(醜陋的)代碼:需要參數的addEventListener(和removeEventListener)函數

root.palmsStatus = ["B","B","B","B","B","B","B","B"]; 

if (root.palmsStatus[0] !== "N") 
    root.game.palms.palm1.addEventListener("click", palmHandler = function(){ palmShakeHandler(1); }); 
if (root.palmsStatus[1] !== "N") 
    root.game.palms.palm2.addEventListener("click", palmHandler = function(){ palmShakeHandler(2); }); 
if (root.palmsStatus[2] !== "N") 
    root.game.palms.palm3.addEventListener("click", function(){ palmShakeHandler(3); }); 
if (root.palmsStatus[3] !== "N") 
    root.game.palms.palm4.addEventListener("click", function(){ palmShakeHandler(4); }); 
if (root.palmsStatus[4] !== "N") 
    root.game.palms.palm5.addEventListener("click", function(){ palmShakeHandler(5); }); 
if (root.palmsStatus[5] !== "N") 
    root.game.palms.palm6.addEventListener("click", function(){ palmShakeHandler(6); }); 
if (root.palmsStatus[6] !== "N") 
    root.game.palms.palm7.addEventListener("click", function(){ palmShakeHandler(7); }); 
if (root.palmsStatus[7] !== "N") 
    root.game.palms.palm8.addEventListener("click", function(){ palmShakeHandler(8); }); 

我有兩個要求:

1)不使用的點擊事件的匿名函數。

我寫了這個代碼,但它不工作

root.game.palms.palm8.addEventListener("click", palmShakeHandler(8)); 

所以這一塊工作正常

root.game.palms.palm8.addEventListener("click", function(){ palmShakeHandler(8); }); 

但我不知道如何刪除事件偵聽器。 我嘗試此解決方案,但它不工作

root.game.palms.palm8.addEventListener("click", palmHandler = function(){ palmShakeHandler(8); }); 
root.game.palms.palm8.removeEventListener("click", palmHandler); 

2)添加和刪除監聽器在用於循環

我寫了如下代碼,但該行爲是不正確的。加入

for (i=1; i <= root.palmsStatus.length; i++){ 
    if (root.palmsStatus[i-1] !== "N"){ 
     root.game.palms["palm" + i].addEventListener("click", function(){ palmShakeHandler(i); }); 
    } 
    } 

聽衆,但傳遞給palmShakeHandler參數的值總是8.

沒有人能幫助我解決這些問題?

回答

4

在JavaScript中使用Function.prototype.bind方法有一個實際的,完美的方法。

bind讓您定義將作爲參數傳遞的函數的額外參數。

您還應該記住bind會創建一個新函數並且不會修改初始函數。

這裏是什麼樣子:

function palmHandler(number) { 
    // your code working with `number` 
} 

var palmHandler8 = palmHandler.bind(null, 8) 
// the palmHandler8 is now tied to the value 8. 
// the first argument (here null) define what `this` is bound to in this function 

這應該可以解決你的問題,你就可以輕鬆移除處理程序:)

您的代碼將是這樣的:

for (i=1; i <= root.palmsStatus.length; i++){ 
    if (root.palmsStatus[i-1] !== "N"){ 
    root.game.palms["palm" + i].addEventListener("click", palmShakeHandler.bind(null, i)); 
    } 
} 

爲了能夠隨後刪除處理程序,您需要保留對您使用bind創建的函數的引用。這將是做到這一點的方式。

var boundHandler = handler.bind(null, i); 
element.addEventListener(boundHandler); 
element.removeEventListener(bounderHander); 

如果您想了解更多關於JavaScript中的真棒bind法,MDN是你的朋友:) https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind

順便說一句,你函數總是返回8是JavaScript的一個非常普遍的問題,這個問題。這個線程將解釋所有的東西(擾流,這是一個範圍:))https://stackoverflow.com/a/750506/2745879

+0

將監聽程序添加到循環中很好。 但刪除它們不起作用 – Zauker

+0

我使用此代碼: root.game.palms [「palm」+ palm] .removeEventListener(「click」,palmShakeHandler); – Zauker

+0

噢,要刪除處理程序,您需要保留對綁定函數的引用並刪除該函數。 'var boundPalm = palm.bind(null,i); addHandler(boundPalm)... removeHandler(boundPalm)' – atomrc

0

在你最後的解決方案中,你正在爲每個函數設置相同的變量,這就是使函數與8一起工作的原因,因爲它是最後一個值的變量。

要工作arround,你可以使用「讓」(請至少使用VAR,otherside,「我」是全球性的,可以在代碼中的每個地方進行更改),但由於我不知道你的目標是什麼,我建議其他解。

for (var i=1; i <= root.palmsStatus.length; i++){ 
    if (root.palmsStatus[i-1] !== "N"){ 
     root.game.palms["palm" + i].addEventListener("click", (function(index) 
     (return function(){ 
     palmShakeHandler(index); 
     }))(i); 
    } 
    } 

由於它看起來像你是針對現代瀏覽器,我會用let。 https://kangax.github.io/compat-table/es6/

for (var i=1; i <= root.palmsStatus.length; i++){ 
    let index = i; 
    let intermediateFunction = function(){palmShakeHandler(index);}; 
    if (root.palmsStatus[i-1] !== "N"){ 
     root.game.palms["palm" + i].addEventListener("click",intermediateFunction); 
     root.game.palms["palm" + i].removeHandShake = function(){this.removeEventListener("click",intermediateFunction)}; 
    } 
    } 

所以,現在你只需要調用「removeHandShake」,將刪除監聽,

我有這個代碼就在這裏,因此緩解了一些小錯誤,彈出

+0

這似乎是一個很好的解決方案,但我不明白如何刪除監聽器添加。 – Zauker

+0

好,因爲你需要做的removeEventListener你需要將它存儲在某處的函數引用,我建議使用閉包。讓我更新最佳答案 –

0

所以,如果你的「棕櫚樹」的陣列非常龐大,將單個事件監聽器添加到每個監聽器中基本上是一個糟糕的想法,因爲這會導致性能缺陷。所以我會建議一個不同的方法:

var handlers = [function (e) {}, …, function (e) {}]; 

root.game.palms.forEach(functiion (palm, idx) { 
    palm.setAttribute('data-idx', idx); 
}); 

<palmsparent>.addEventListener('click', function (e) { 
    var c = e.target, idx = -1; 

    while (c) { 
    if (c.hasAttribute && c.hasAttribute('data-idx')) { 
     idx = parseInt(c.getAttribute('data-idx')); 
     break; 
    } 
    c = c.parentNode; 
    } 

    //here you also check for the »palm status« 
    if (idx >= 0) { 
    handlers[idx](c); 
    } 
}) 

所有的事件監聽器,更容易移除和更好的性能。

相關問題