2016-05-13 34 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

相關問題