JavaScript - добавление прослушивателя событий в массив объектов - PullRequest
0 голосов
/ 02 июля 2018

Я новичок в языке JavaScript, поэтому, пожалуйста, помогите мне понять, где я ошибаюсь с этой проблемой. Я пытаюсь включать и выключать класс done при нажатии элемента списка . Но я получаю эту ошибку "Uncaught TypeError: Невозможно прочитать свойство 'classList' undefined at HTMLLIElement".

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 голосов
/ 02 июля 2018

//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>
0 голосов
/ 02 июля 2018

При добавлении прослушивателя событий вы создаете замыкание. Каждый обработчик событий имеет переменную 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>
  • объявление i с let вместо var в вашем цикле for. Это приведет к тому, что каждое ваше закрытие будет иметь различную привязку с 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>

Подробнее о закрытиях JavaScript.

0 голосов
/ 02 июля 2018

Для повышения производительности вашего кода вы можете использовать делегирование события . С помощью этой техники вам просто нужно один раз добавить слушателя в контейнер (в данном случае ul), и все дочерние элементы будут иметь к нему доступ. Затем вы можете использовать свойство event.target для нацеливания на каждый элемент li:

var ul = document.querySelector("ul");
ul.addEventListener('click', function(event){
  event.target.classList.toggle("done");
});
0 голосов
/ 02 июля 2018

Изменение

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

до

this.classList.toggle("done");

... в противном случае при обратном вызове события вы всегда будете нацеливаться на li, представленное последним значением i, а не тем, которое было щелкнуто.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...