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

时间:2018-07-02 10:38:48

标签: javascript html arrays events dom

我是JavaScript语言的新手,请帮助我了解该问题出了哪些问题。 我正在尝试单击列表项时打开和关闭完成的类。但是我遇到了“未捕获的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>

4 个答案:

答案 0 :(得分:1)

更改

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

this.classList.toggle("done");

...否则,在事件回调中,您将始终以li的最后一个值表示的i为目标,而不是被单击的那个。

答案 1 :(得分:1)

要提高代码的性能,可以使用事件委托。使用这种技术,您只需要向容器(在本例中为ul)中添加一次侦听器,所有子代都可以访问它。然后,您可以使用 event.target 属性定位每个li项目:

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

答案 2 :(得分:0)

添加事件监听器时,您正在创建一个闭包。每个事件处理程序在其作用域内都有变量i。不幸的是,它是相同的变量i,由您的for循环递增。

在循环结束时,每个事件处理程序在其作用域内都有一个变量i,其值现在为6。这将导致在触发事件时未定义li[i]

您可以通过以下方法解决此问题:

  • 未在处理程序中使用i,例如,通过使用提供的event变量来引用事件。然后,检索目标元素:

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>

  • 在您的for循环中使用i而不是let声明var。这将导致您的每个闭包与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>

  • 将事件侦听器附加到UL。这将是我的最爱:

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.

答案 3 :(得分:0)

//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>