简体   繁体   English

JavaScript-将事件侦听器添加到对象数组

[英]JavaScript - Adding event listener to an array of objects

I am new to the JavaScript Language so please help me understand where I am going wrong with this issue. 我是JavaScript语言的新手,所以请帮助我了解该问题出了哪些问题。 I am trying to toggle the done class on and off when a list item is clicked . 我试图在单击列表项时打开和关闭完成的类 But I am getting this "Uncaught TypeError: Cannot read property 'classList' of undefined at HTMLLIElement" error. 但是,我收到此“未捕获的TypeError:无法读取HTMLLIElement处未定义的属性'classList'”错误。

 var li = document.querySelectorAll("li"); for (var i = 0; i < li.length; i++) { li[i].addEventListener("click", function() { li[i].classList.toggle("done"); }) } 
 .done { text-decoration: line-through; } 
 <h1>Shopping List</h1> <ul style="list-style-type:square"> <li>Pencil</li> <li>Paper</li> <li>Eraser</li> <li>Table Lamp</li> <li>Comb</li> </ul> 

Change 更改

li[i].classList.toggle("done");

to

this.classList.toggle("done");

...otherwise in the event callback you'll always be targeting the li represented by the last value of i , not the one that was clicked. ...否则,在事件回调中,您将始终以i的最后一个值表示的li为目标,而不是单击的那个。

To improve the performance of your code, you can use event delegation . 为了提高代码的性能,可以使用事件委托 With that technique, you just need to add the listener once, to the container (in this case, the ul), and all the children will have access to it. 使用这种技术,您只需要向容器(在本例中为ul)中添加一次侦听器,所有子代都可以访问它。 Then, you can use the event.target property to target every li item: 然后,您可以使用event.target属性来定位每个li项目:

var ul = document.querySelector("ul");
ul.addEventListener('click', function(event){
  event.target.classList.toggle("done");
});

When adding your event listener, you are creating a closure. 添加事件监听器时,您正在创建一个闭包。 Each event handler has the variable i in their scope. 每个事件处理程序在其范围内都有变量i Unfortunately, it's the same variable i , the one that's incremented by your for loop. 不幸的是,它是相同的变量i ,它由您的for循环递增。

At the end of the loop, each event handler has, in its scope, a variable i whose value is now 6. It results in li[i] being undefined when the event is fired. 在循环结束时,每个事件处理程序在其范围内都有一个变量i其值现在为6。这导致在触发事件时未定义li[i]

You can solve this by, either : 您可以通过以下方法解决此问题:

  • not using i in your handler, for instance by using the provided event variable, that references the event. 不要在处理程序中使用i ,例如通过使用提供的event变量来引用事件。 And thourh it, retrieves the targeted element : 然后,检索目标元素:

 var li = document.querySelectorAll("li"); for (var i = 0; i < li.length; i++) { li[i].addEventListener("click", function(event) { event.target.classList.toggle("done"); }) } 
 .done { text-decoration: line-through; } 
 <h1>Shopping List</h1> <ul style="list-style-type:square"> <li>Pencil</li> <li>Paper</li> <li>Eraser</li> <li>Table Lamp</li> <li>Comb</li> </ul> 

  • declaring i with let instead of var in your for loop. 在for循环中使用let而不是var声明i This will result in each of your closure to have a different binding with i : 这将导致您的每个闭包与i具有不同的绑定:

 var li = document.querySelectorAll("li"); for (let i = 0; i < li.length; i++) { li[i].addEventListener("click", function() { li[i].classList.toggle("done"); }) } 
 .done { text-decoration: line-through; } 
 <h1>Shopping List</h1> <ul style="list-style-type:square"> <li>Pencil</li> <li>Paper</li> <li>Eraser</li> <li>Table Lamp</li> <li>Comb</li> </ul> 

  • attaching the event listener to the UL. 将事件侦听器附加到UL。 This would be my favorite : 这将是我的最爱:

 var ul = document.querySelector("ul"); ul.addEventListener("click", function(event) { event.target.classList.toggle("done"); }, true); 
 .done { text-decoration: line-through; } 
 <h1>Shopping List</h1> <ul style="list-style-type:square"> <li>Pencil</li> <li>Paper</li> <li>Eraser</li> <li>Table Lamp</li> <li>Comb</li> </ul> 

Read more about JavaScript closures. 阅读有关JavaScript闭包的更多信息。

 //using for of loop var li = document.querySelectorAll("li"); for (var i of li) { i.addEventListener('click', function(e) { e.target.classList.toggle("done"); }) } 
 .done { text-decoration: line-through; } 
 <h1>Shopping List</h1> <ul style="list-style-type:square"> <li>Pencil</li> <li>Paper</li> <li>Eraser</li> <li>Table Lamp</li> <li>Comb</li> </ul> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM