addEventListener使用for循环和传递值

use*_*172 75 javascript for-loop addeventlistener

我正在尝试使用for循环向多个对象添加事件侦听器,但最终会将所有侦听器定位到同一个对象 - >最后一个.

如果我通过为每个实例定义boxa和boxb来手动添加侦听器,它就可以工作.我想这就是addEvent for-loop,它不像我希望的那样工作.也许我完全使用了错误的方法.

使用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);
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

Hal*_*yon 116

瓶盖!:d

此固定代码按预期工作:

// 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
}
Run Code Online (Sandbox Code Playgroud)

为什么要修复它?

<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>
Run Code Online (Sandbox Code Playgroud)

实际上是非严格的JavaScript.它的解释如下:

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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

使用封闭(封闭的值boxa,boxb等),你绑定值单击处理的范围.


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

  • 应该`}(i,k))```})(i,k)`? (2认同)
  • *实际上是无效的 JavaScript。*:如果无效,则不会解析或执行。*使用我向您展示的闭包,您确实得到了您期望的行为*:正确,但重要的是您正在*执行*循环内的一个函数,它创建了一个新的作用域。 (2认同)

ten*_*its 12

您将范围/闭包问题视为function(){makeItHappen(boxa,boxb);} boxaboxb引用,然后始终是最后一个元素.

要解决这个问题:

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

// ...
 elem[i].addEventListener("click", makeItHappenDelegate(boxa,boxb), false);
Run Code Online (Sandbox Code Playgroud)

  • 嗯,即使在可读性和可维护性方面,委托也是更好的方法.**固体 (2认同)

msa*_*tos 6

你可以使用Function Binding.You不需要使用闭包.见下:

之前:

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);
   }
}
Run Code Online (Sandbox Code Playgroud)

之后:

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);
   }
}
Run Code Online (Sandbox Code Playgroud)