addEventListener不正常工作

9 浏览
0 Comments

addEventListener不正常工作

这个问题已经有了答案:
JavaScript中循环内部的闭包 – 简单实用的例子

我正在尝试使用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);
}


some text

 

some text

 

some text

 

some text

 

admin 更改状态以发布 2023年5月22日
0
0 Comments

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

之前:

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

之后:

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

0
0 Comments

闭包!: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
}


    

some text

some text

some text

some text


为什么要这样修正呢?

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

实际上是非严格模式的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);
}

因为变量提升,var声明被移到了作用域的顶部。由于JavaScript没有块级作用域(例如forifwhile等),它们被移到了函数的顶部。 更新:自ES6以来,你可以使用 let 来获取块级作用域变量。

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

使用闭包(将boxaboxb等的值封闭)将值绑定到点击处理程序的作用域。


代码分析工具(如JSLintJSHint)将能够捕捉到这种可疑的代码。如果你在写大量的代码,那么学习如何使用这些工具是值得的。有些IDE内置了它们。

0