javascript - for 循环 - 仅每隔一个事件侦听器工作

javascript - for loop - only every second event listener working

我是网页设计的新手,所以我确定我在这里做了一些愚蠢的事情,但我真的很好奇我做错了什么,我正在做一个在线 udemy 课程,出于某种原因,li 的每两次迭代我 spawn 似乎附加了我的事件侦听器,但我终究无法弄清楚原因。我假设在添加事件侦听器时它与我的“this”有关,我试图更改为 listObjects[i].classList.toggle 但它只是抛出了一个错误但是奇怪的是如果我做 this.classList.add("完成") 它完美地工作。提前致谢!

var enterBtn = document.querySelectorAll("button")[0];
var cancelBtn = document.querySelectorAll("button")[1];
var ul = document.querySelector("ul");
var listObjects

function addList(todo) {
  var li = document.createElement("li");
  li.appendChild(document.createTextNode(todo));
  ul.appendChild(li);
  listObjects = document.querySelectorAll("li");
  setListDone();
}

enterBtn.addEventListener("click", function() {
  var listData = document.querySelector("input").value;
  addList(listData);
});

cancelBtn.addEventListener("click", function() {
  ul.innerHTML = " ";
});

function setListDone() {
  for (i = 0; i < listObjects.length; i++) {
    listObjects[i].addEventListener("click", function() {
      this.classList.toggle("done");
    });
  }
}
.done {
  text-decoration: line-through;
}
<h1>Todo List</h1>
<input type="text">
<button>Enter</button>
<button>Cancel</button>
<ul>
</ul>

您永远不会删除旧的事件侦听器,因此具有偶数索引的任何内容都会被切换两次(或四次,或其他),并以与开始时相同的状态结束。如果您先清除旧的事件侦听器(或仅将它们添加到新创建的元素),问题就会消失:

var enterBtn = document.querySelectorAll("button")[0];
var cancelBtn = document.querySelectorAll("button")[1];
var ul = document.querySelector("ul");
var listObjects

function addList(todo) {
  var li = document.createElement("li");
  li.appendChild(document.createTextNode(todo));
  ul.appendChild(li);
  listObjects = document.querySelectorAll("li");
  setListDone();
}

enterBtn.addEventListener("click", function() {
  var listData = document.querySelector("input").value;
  addList(listData);
});

cancelBtn.addEventListener("click", function() {
  ul.innerHTML = " ";
});

function setListDone() {
  for (i = 0; i < listObjects.length; i++) {
    listObjects[i].removeEventListener("click", liClickHandler);
    listObjects[i].addEventListener("click", liClickHandler);
  }
}

function liClickHandler() {
      this.classList.toggle("done");
}
.done {
  text-decoration: line-through;
}
<h1>Todo List</h1>
<input type="text">
<button>Enter</button>
<button>Cancel</button>
<ul>
</ul>

原因是您正在使用 setListDoneclick 分配给所有 li。因此,当您添加第二个 li 时,它也会将 click 分配给 first li。所以当你点击第一个 li 时,它会调用 click twice。此外,如果您添加第三个 li 然后在 first li 上单击它将调用 click three times.

要解决问题,您只需将新创建的 li 传递给 setListDone 并如下更新您的 setListDone

function setListDone(li) {
  li.addEventListener("click", function() {
    this.classList.toggle("done");
  });
}

测试下面的完整代码。

var enterBtn = document.querySelectorAll("button")[0];
var cancelBtn = document.querySelectorAll("button")[1];
var ul = document.querySelector("ul");
var listObjects

function addList(todo) {
  var li = document.createElement("li");
  li.appendChild(document.createTextNode(todo));
  ul.appendChild(li);
  listObjects = document.querySelectorAll("li");
  setListDone(li);
}

enterBtn.addEventListener("click", function() {
  var listData = document.querySelector("input").value;
  addList(listData);
});

cancelBtn.addEventListener("click", function() {
  ul.innerHTML = " ";
});

function setListDone(li) {
  li.addEventListener("click", function() {
    this.classList.toggle("done");
  });
}
.done {
  text-decoration: line-through;
}
<h1>Todo List</h1>
<input type="text">
<button>Enter</button>
<button>Cancel</button>
<ul>
</ul>

每次将项目添加到列表时,您都会为每个项目添加事件侦听器。这就是为什么其中一些会被触发两次或更多次的原因。

listObjects[i].addEventListener("click", function() {
  this.classList.toggle("done");
});

简单的解决方案如下。

每次向列表添加元素时,您只需要将事件侦听器添加到 单个 <li>

var enterBtn = document.querySelectorAll("button")[0];
var cancelBtn = document.querySelectorAll("button")[1];
var ul = document.querySelector("ul");
var listObjects

function addList(todo) {
  var li = document.createElement("li");
  li.appendChild(document.createTextNode(todo));
  // Here you add the listener to just created list item
  li.addEventListener("click", function() {
      this.classList.toggle("done");
  });
  ul.appendChild(li);
}

enterBtn.addEventListener("click", function() {
  var listData = document.querySelector("input").value;
  addList(listData);
});

cancelBtn.addEventListener("click", function() {
  ul.innerHTML = " ";
});
.done {
  text-decoration: line-through;
}
<h1>Todo List</h1>
<input type="text">
<button>Enter</button>
<button>Cancel</button>
<ul>
</ul>