javascript addEventListener 使用 for 循环和传递值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19586137/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 16:04:11  来源:igfitidea点击:

addEventListener using for loop and passing values

javascriptfor-loopaddeventlistener

提问by user2919172

I'm trying to add event listener to multiple objects using a for loop, but end up with all listeners targeting the same object --> the last one.

我正在尝试使用 for 循环向多个对象添加事件侦听器,但最终所有侦听器都针对同一对象 --> 最后一个。

If I add the listeners manually by defining boxa and boxb for every instance, it works. I guess it's the addEvent for-loop that's not working the way I hoped for. Maybe I use the wrong approach altogether.

如果我通过为每个实例定义 boxa 和 boxb 手动添加侦听器,它会起作用。我猜是 addEvent for 循环没有按我希望的方式工作。也许我完全使用了错误的方法。

Example using 4 of the class="container" Trigger on container 4 works the way it′s supposed to. Trigger on container 1,2,3 trigger event on container 4, but only if trigger has already been activated.

在容器 4 上使用 class="container" 触发器的 4 的示例按预期的方式工作。触发容器 1、2、3 触发容器 4 上的事件,但前提是触发器已被激活。

// Function to run on click:
function makeItHappen(elem, elem2) {
  var el = document.getElementById(elem);
  el.style.backgroundColor = "red";
  var el2 = document.getElementById(elem2);
  el2.style.backgroundColor = "blue";
}

// Autoloading function to add the listeners:
var elem = document.getElementsByClassName("triggerClass");

for (var i = 0; i < elem.length; i += 2) {
  var k = i + 1;
  var boxa = elem[i].parentNode.id;
  var boxb = elem[k].parentNode.id;

  elem[i].addEventListener("click", function() {
    makeItHappen(boxa, boxb);
  }, false);
  elem[k].addEventListener("click", function() {
    makeItHappen(boxb, boxa);
  }, false);
}
<div class="container">
  <div class="one" id="box1">
    <p class="triggerClass">some text</p>
  </div>
  <div class="two" id="box2">
    <p class="triggerClass">some text</p>
  </div>
</div>

<div class="container">
  <div class="one" id="box3">
    <p class="triggerClass">some text</p>
  </div>
  <div class="two" id="box4">
    <p class="triggerClass">some text</p>
  </div>
</div>

回答by Halcyon

Closures! :D

关闭!:D

This fixed code works as you intended:

此固定代码按您的预期工作:

// Function to run on click:
function makeItHappen(elem, elem2) {
    var el = document.getElementById(elem);
    el.style.backgroundColor = "red";
    var el2 = document.getElementById(elem2);
    el2.style.backgroundColor = "blue";
}

// Autoloading function to add the listeners:
var elem = document.getElementsByClassName("triggerClass");

for (var i = 0; i < elem.length; i += 2) {
    (function () {
        var k = i + 1;
        var boxa = elem[i].parentNode.id;
        var boxb = elem[k].parentNode.id;
        elem[i].addEventListener("click", function() { makeItHappen(boxa,boxb); }, false);
        elem[k].addEventListener("click", function() { makeItHappen(boxb,boxa); }, false);
    }()); // immediate invocation
}
<div class="container">
  <div class="one" id="box1">
    <p class="triggerClass">some text</p>
  </div>
  <div class="two" id="box2">
    <p class="triggerClass">some text</p>
  </div>
</div>

<div class="container">
  <div class="one" id="box3">
    <p class="triggerClass">some text</p>
  </div>
  <div class="two" id="box4">
    <p class="triggerClass">some text</p>
  </div>
</div>



Why does this fix it?

为什么要解决这个问题?

for(var i=0; i < elem.length; i+=2){
    var k = i + 1;
    var boxa = elem[i].parentNode.id;
    var boxb = elem[k].parentNode.id;

    elem[i].addEventListener("click", function(){makeItHappen(boxa,boxb);}, false);
    elem[k].addEventListener("click", function(){makeItHappen(boxb,boxa);}, false);
}

Is actually non-strict JavaScript. It's interpretted like this:

实际上是非严格的 JavaScript。它的解释是这样的:

var i, k, boxa, boxb;
for(i=0; i < elem.length; i+=2){
    k = i + 1;
    boxa = elem[i].parentNode.id;
    boxb = elem[k].parentNode.id;

    elem[i].addEventListener("click", function(){makeItHappen(boxa,boxb);}, false);
    elem[k].addEventListener("click", function(){makeItHappen(boxb,boxa);}, false);
}

Because of variable hoisting, the vardeclarations get moved to the top of the scope. Since JavaScript doesn't have block scope (for, if, whileetc.) they get moved to the top of the function. Update:as of ES6 you can use letto get block scoped variables.

由于变量提升var声明被移到了作用域的顶部。由于JavaScript没有块作用域(forifwhile等),他们无法移动到函数的顶部。更新:从 ES6 开始,您可以使用let获取块作用域变量。

When your code runs the following happens: in the forloop you add the click callbacks and you assign boxa, but its value gets overwritten in the next iteration. When the click event fires the callback runs and the value of boxais alwaysthe last element in the list.

当您的代码运行时,会发生以下情况:在for循环中添加点击回调并分配boxa,但它的值在下一次迭代中被覆盖。当点击事件触发回调运行和的值boxa始终在列表的最后一个元素。

Using a closure (closing the values of boxa, boxbetc) you bind the value to the scope of the click handler.

使用封闭(封闭的值boxaboxb等),你的值绑定到单击处理的范围。



Code analysis tools such JSLintor JSHintwill be able to catch suspicious code like this. If you're writing a lot of code it's worthwhile to take the time to learn how to use these tools. Some IDEs have them built-in.

代码分析工具等的JSLintJSHint将能够赶上可疑这样的代码。如果您要编写大量代码,那么花时间学习如何使用这些工具是值得的。一些 IDE 内置了它们。

回答by tenbits

You facing the scope/closure problem as function(){makeItHappen(boxa,boxb);}boxaand boxbreferences then always the last one element(s).

您面临范围/闭包问题作为function(){makeItHappen(boxa,boxb);}boxaboxb引用然后总是最后一个元素。

To solve the issue:

要解决这个问题:

function makeItHappenDelegate(a, b) {
  return function(){
      makeItHappen(a, b)
  }
}

// ...
 elem[i].addEventListener("click", makeItHappenDelegate(boxa,boxb), false);

回答by msantos

You can use Function Binding.You dont need use closures.See below:

你可以使用函数绑定。你不需要使用闭包。见下文:

Before:

之前

function addEvents(){
   var elem = document.getElementsByClassName("triggerClass");

   for(var i=0; i < elem.length; i+=2){
      var k = i + 1;
      var boxa = elem[i].parentNode.id;
      var boxb = elem[k].parentNode.id;

      elem[i].addEventListener("click", function(){makeItHappen(boxa,boxb);}, false);
      elem[k].addEventListener("click", function(){makeItHappen(boxb,boxa);}, false);
   }
}

After:

之后

function addEvents(){
   var elem = document.getElementsByClassName("triggerClass");

   for(var i=0; i < elem.length; i+=2){
        var k = i + 1;
      var boxa = elem[i].parentNode.id;
      var boxb = elem[k].parentNode.id;
      elem[i].addEventListener("click", makeItHappen.bind(this, boxa, boxb), false);
      elem[k].addEventListener("click", makeItHappen.bind(this, boxa, boxb), false);
   }
}

回答by olindk

It's because of closures.

这是因为关闭。

Check this out: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures#Creating_closures_in_loops_A_common_mistake

看看这个:https: //developer.mozilla.org/en-US/docs/Web/JavaScript/Closures#Creating_closures_in_loops_A_common_mistake

The sample code and your code is essentially the same, it's a common mistake for those don't know "closure".

示例代码和你的代码本质上是一样的,对于不知道“闭包”的人来说,这是一个常见的错误。

To put it simple, when your create a handler function inside addEvents(), it does not just accesses the variable ifrom the addEvents()'s environment, but it also "remembers" i.

简而言之,当您在 内部创建处理程序函数时addEvents(),它不仅会iaddEvents()的环境中访问变量,而且还会“记住” i

And because your handler "remembers" i, the variable iwon't vanish after addEvents()was executed.

并且因为您的处理程序“记住” i,变量iaddEvents()执行后不会消失。

So when the handler is called, it will use the ibut the variable iis now, after the for-loop, 3.

因此,当处理程序被调用时,它将使用 ,i但变量i现在是,在 for 循环之后,3。

回答by blue3d

I also had this problem a while ago. I solved it by using a "adds" function outside the loop, to assign events, and it worked perfectly.

不久前我也遇到了这个问题。我通过在循环外使用“添加”函数来分配事件来解决它,并且它工作得很好。

Your script should look like.

你的脚本应该看起来像。

function addEvents(){
  var elem = document.getElementsByClassName("triggerClass");
  for(var i=0; i < elem.length; i+=2){
    var k = i + 1;
    var boxa = elem[i].parentNode.id;
    var boxb = elem[k].parentNode.id;

//- edit ---------------------------|
    adds(boxa, boxb);
  }
}
//- adds function ----|
function adds(obj1, obj2){
  obj1.addEventListener("click", function(){makeItHappen(obj1, obj2);}, false);
  obj2.addEventListener("click", function(){makeItHappen(obj1, obj2);}, false);
}
//- end edit -----------------------|

function makeItHappen(elem, elem2){
  var el = document.getElementById(elem);
  el.style.transform = "flip it";
  var el2 = document.getElementById(elem2);
  el2.style.transform = "flip it";
}