需要参数的 addEventListener(和 removeEventListener)函数

addEventListener (and removeEventListener) function that need param

我需要为 8 个对象(手掌)添加一些侦听器。 这些对象是相同的,但行为必须根据它们的位置而改变。 我有以下(丑陋的)代码:

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 循环中添加和删除侦听器

我写了以下代码,但行为不正确。

  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。

没有人可以帮我解决这些问题吗?

在 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 中是一个很常见的问题。该线程将解释所有内容(剧透,这是范围界定的问题:))

在上一个解决方案中,您将相同的 var 传递给每个函数,这就是使所有函数都使用 8 的原因,因为 8 是变量的最后一个值。

为了解决问题,您可以使用 "let"(请至少使用 var,除此之外 "i" 是全局的,可以在代码中的每个地方进行更改)但是因为我不知道哪个浏览器你的目标我提出其他解决方案。

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" 并删除监听器,

我这里有这个代码,所以它可以减少弹出的一些小错误

因此,如果您的 »palms« 数组非常大,为每个数组添加一个事件侦听器基本上不是一个好主意,因为这会导致性能缺陷。所以我建议采用不同的方法:

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);
  }
})

所有人的一个事件侦听器,更容易删除并且性能更好。