2016-05-13 31 views
0
function recordData(){ 
    var element = document.getElementsByClassName("bubble"); 
    for(var i = 0; i < element.length; i++){ 
     element[i].addEventListener("click", function(){ 
      var id = element[i].attributes.id.value; 
      var x_cordinate = element[i].children[2].attributes.x.value; 
      var y_cordinate = element[i].children[2].attributes.y.value; 
      var keyword = element[i].children[0].textContent; 
      clicked_elements.push({ 
       id: id, 
       x_cordinate: x_cordinate, 
       y_cordinate: y_cordinate, 
       keyword: keyword 
      }) 
     }, false); 
    } 
} 

当我尝试单击html中的元素时,它显示错误“Uncaught TypeError:无法读取未定义的属性'属性'。我无法在addEventListener方法中访问该特定元素的id和其他属性。如果我需要记录点击的内容,请解释我在这里做错了什么。无法注册事件处理程序到javascript中的元素数组

+2

您可以使用'this'来引用事件侦听器函数中的clicked元素。你会陷入麻烦,因为在你的for循环中'i'正在改变。 – user3297291

+0

你可以通过使用IIFE来解决这个问题(var i = 0; i jcubic

+0

参考这项工作!谢谢 ! –

回答

0

function recordData(){ 
 
\t var element = document.getElementsByClassName("bubble"); 
 
\t for(var i = 0; i < element.length; i++){ 
 
\t \t element[i].addEventListener("click", function(){ 
 
\t \t \t var id = this.attributes.id.value; 
 
\t \t \t var x_cordinate = this.children[2].attributes.x.value; 
 
\t \t \t var y_cordinate = this.children[2].attributes.y.value; 
 
\t \t \t var keyword = this.children[0].textContent; 
 

 
\t \t \t clicked_elements.push({ 
 
\t \t \t \t id: id, 
 
\t \t \t \t x_cordinate: x_cordinate, 
 
\t \t \t \t y_cordinate: y_cordinate, 
 
\t \t \t \t keyword: keyword 
 
\t \t \t }) 
 
\t \t }, false); 
 
\t } 
 
}

这是我的代码的最终版本,运行正常。 'this'帮助我访问事件监听器中的对象。

1

您不能在addEventListener回调中使用i,因为它将在for循环结束后执行。

使用this代替elements[i]获得瓶盖内的当前元素。

0

您正在运行一个与Javascript相同的问题,在'for'您正在注册基于i值的事件处理程序时,它被触发的事件'i'的值等于'element.length'返回undefined这是你得到你的错误的原因。

为了解决这个问题,你需要做一个clousere以保持到阵列不是指数的元素的引用。尝试使用Array.forEach而不是'for'。

这里同比CON鳍更info倒闭如何工作的。

1

你这里的问题是,可变i不会有你认为它会具有的价值。这是由于关闭如何工作。

试试这个简单的例子:

for(var i = 0; i < 5; i++) { 
    console.log("Before timeout: " + i); 
    setTimeout(function() { 
     console.log("After timeout: " + i); 
    }, 1000); 
} 

当您运行此,你会期待什么?可能在一秒钟后,你在控制台中看到了这一点?

Before timeout: 0 
Before timeout: 1 
Before timeout: 2 
Before timeout: 3 
Before timeout: 4 
After timeout: 0 
After timeout: 1 
After timeout: 2 
After timeout: 3 
After timeout: 4 

但你猜怎么着,你会看到这一点:

Before timeout: 0 
Before timeout: 1 
Before timeout: 2 
Before timeout: 3 
Before timeout: 4 
After timeout: 5 
After timeout: 5 
After timeout: 5 
After timeout: 5 
After timeout: 5 

为什么5? for声明基本上将i设置为0,然后在每次迭代中对其进行计数并每次检查它是否仍低于5,如果不是,则打破循环。因此,在循环后,i有值为5,这样的:

​​

...给:

After loop: 5 

好,但为什么使用值i在循环之后有?这是因为您传递给setTimeout的函数回调直接访问外部范围中的i变量!而且因为函数只会在一秒后运行(在循环完成之后),此时i的值将为5,如上所示!

因此,解决办法是创建这个变量,它是本地的每次迭代的本地副本。现在,这是不是因为它似乎是因为在JavaScript中,像for控制块不会创建范围(除非你使用ES6和let)微不足道。你必须使用另一个匿名函数围绕它来创建一个本地副本,每次它是那么的不同:

for(var i = 0; i < 5; i++) { 
    // This is a so-called "immediately executed function expression" 
    // It's an anonymous function which is then immediately called due 
    // to the `()` at the end. 
    (function() { 
     var j = i; // Now we have a local `j` 
     console.log("Before timeout: " + j); 
     setTimeout(function() { 
      console.log("After timeout: " + j); 
     }, 1000); 
    })(); 
} 

另一种方式由于这一点,这是一个有点短,是这一招:

for(var i = 0; i < 5; i++) { 
    // See how this anonymous function now takes a parameter `i`? 
    // And we pass this parameter when calling this function below, 
    // which basically creates an inner copy which we can now also call 
    // `i`. 
    (function(i) { 
     console.log("Before timeout: " + i); 
     setTimeout(function() { 
      console.log("After timeout: " + i); 
     }, 1000); 
    })(i); 
} 

这就是为什么我建议在迭代数组时使用类似forEach的东西,因为它们将函数回调作为参数,所以您自动在代码中有一个本地作用域。

现在你的情况,你可以使用上面的一个匿名函数解决方案,或者类似forEach,但有一个问题:element变量不是普通的JavaScript数组,它是一个DOM元素列表,它没有forEach。但是,你仍然可以使它工作使用Array.prototype.forEach.call招:

function recordData(){ 
    var element = document.getElementsByClassName("bubble"); 
    Array.prototype.forEach.call(element, function(i) { 
     element[i].addEventListener("click", function(){ 
      var id = element[i].attributes.id.value; 
      var x_cordinate = element[i].children[2].attributes.x.value; 
      var y_cordinate = element[i].children[2].attributes.y.value; 
      var keyword = element[i].children[0].textContent; 
      clicked_elements.push({ 
       id: id, 
       x_cordinate: x_cordinate, 
       y_cordinate: y_cordinate, 
       keyword: keyword 
      }) 
     }, false); 
    }); 
} 

之前,因为你有效利用element[element.length].attributes(因为i已经是一个超出你的数组上限的),没有工作,所以element[i]是未定义。

你走了!

但是,更好的方法是使用this,因为在事件侦听器中,this引用事件的目标。因此,而不是element[i],您可以在听众中随处使用this

相关问题