【问题标题】:forEach can't read new node elements - jsforEach 无法读取新的节点元素 - js
【发布时间】:2018-12-29 17:17:39
【问题描述】:

我用 JS 编写了一个非常简单的 Todo 应用程序。它工作正常,我有一些默认任务,我可以单击它们将它们更改为已完成或撤消,但问题是当我添加新任务时,我无法对其执行任何操作。

const input   = document.querySelector('#todoText');
const todo  = document.querySelector('#todo');
const todoLi  = document.querySelectorAll('#todo li');

// Add Todo
input.addEventListener('keyup', e => {
  if (e.keyCode === 13) {
    // Get input value
    let val = e.target.value;
    // Create <li>
    const li = document.createElement('li');
    // Create text node from input value
    let text = document.createTextNode(val);
    // Pass input value into <li>
    li.appendChild(text);
    // Add input value in Todo list
    todo.appendChild(li);
    // Reset input value after enter
    e.target.value = '';
  }
})


todoLi.forEach( item => {
  item.addEventListener('click', e => {

    if ( e.target.classList.contains('done') ) {
      e.target.classList.remove('done')
    } else {
      e.target.classList.add('done')
    }

  })
})

这是我在 Codepen 上的PEN

【问题讨论】:

标签: javascript dom foreach event-handling closures


【解决方案1】:

添加

li.addEventListener('click', e => {
  if ( e.target.classList.contains('done') ) {
    e.target.classList.remove('done')
  } else {
    e.target.classList.add('done')
  }
});

之后

li.appendChild(text);

在将节点插入 DOM 之前在节点上添加点击监听器。

分叉和固定的sn-p:

const input   = document.querySelector('#todoText');
const todo  = document.querySelector('#todo');
const todoLi  = document.querySelectorAll('#todo li');

// Add Todo
input.addEventListener('keyup', e => {
  if (e.keyCode === 13) {
    // Get input value
    let val = e.target.value;
    // Create <li>
    const li = document.createElement('li');
    // Create text node from input value
    let text = document.createTextNode(val);
    // Pass input value into <li>
    li.appendChild(text);
    
    li.addEventListener('click', e => {
  if ( e.target.classList.contains('done') ) {
    e.target.classList.remove('done')
  } else {
    e.target.classList.add('done')
  }
});
    // Add input value in Todo list
    todo.appendChild(li);
    // Reset input value after enter
    e.target.value = '';
  }
})


todoLi.forEach( item => {
  item.addEventListener('click', e => {
    
    if ( e.target.classList.contains('done') ) {
      e.target.classList.remove('done')
    } else {
      e.target.classList.add('done')
    }

  })
})
body {
  margin: 50px;
}

input {
  padding: 5px 15px;
  background: #eee;
  border: 0;
  width: 100%;
  margin-left: 10px;
  border: solid 2px #eee;
  border-radius: 50px;
  transition: all 350ms;
  font-size: 12px;
  &:focus {
    border: solid 2px #eee;
    background: #fff;
    outline: none;
  }
}

ul {
  li {
    position: relative;
    cursor: pointer;
    transition: all 350ms;
    &:hover {
      &:before {
        content: '?';
        position: absolute;
        left: -25px
      }
    }
  }
}

.done {
  text-decoration: line-through;
  color: #888;
}
<div class="d-flex align-items-center mb-5">
  <span class="font-weight-bold text-muted">TODO:</span>
  <input id="todoText" placeholder="Write something and press Enter">
</div>

<small>Todo list:</small>
<ul id="todo">
  <li>Add something new ?</li>
  <li>This is a todo app with JS ?</li>
  <li class="done">I'm a done task ??</li>
</ul>

<hr>

【讨论】:

  • 前面的元素没有变化
  • @ArmanShojaei 我不知道你的意思是什么,但它显然确实有效,正如你现在可以在我添加到我的答案中的 sn-p 中看到的那样。
  • 是的,它的工作,谢谢,但我不明白,你能解释一下吗?
【解决方案2】:

您可以通过将click 事件侦听器添加到#todo 而不是li 元素来解决您的问题并简化您的代码:

const input = document.querySelector('#todoText');
const todo = document.querySelector('#todo');

// Add Todo
input.addEventListener('keyup', e => {
  if (e.keyCode === 13) {
    // Get input value
    let val = e.target.value;
    // Create <li>
    const li = document.createElement('li');
    // Create text node from input value
    let text = document.createTextNode(val);
    // Pass input value into <li>
    li.appendChild(text);
    // Add input value in Todo list
    todo.appendChild(li);
    // Reset input value after enter
    e.target.value = '';
  }
})


todo.addEventListener('click', e => {
  var li = e.target;
  while (li.nodeName.toLowerCase() !== 'li') {
    if (li === this) return;
    li = li.parentNode;
  }
  li.classList.toggle('done')
})
body {
  margin: 50px;
}

input {
  padding: 5px 15px;
  background: #eee;
  border: 0;
  width: 100%;
  margin-left: 10px;
  border: solid 2px #eee;
  border-radius: 50px;
  transition: all 350ms;
  font-size: 12px;
  &:focus {
    border: solid 2px #eee;
    background: #fff;
    outline: none;
  }
}

ul {
  li {
    position: relative;
    cursor: pointer;
    transition: all 350ms;
    &:hover {
      &:before {
        content: '?';
        position: absolute;
        left: -25px
      }
    }
  }
}

.done {
  text-decoration: line-through;
  color: #888;
}
<div class="d-flex align-items-center mb-5">
  <span class="font-weight-bold text-muted">TODO:</span>
  <input id="todoText" placeholder="Write something and press Enter">
</div>

<small>Todo list:</small>
<ul id="todo">
  <li>Add something new ?</li>
  <li>This is a todo app with JS ?</li>
  <li class="done">I'm a done task ??</li>
</ul>

<hr>

【讨论】:

    猜你喜欢
    • 2018-04-16
    • 2020-09-25
    • 1970-01-01
    • 2017-09-10
    • 1970-01-01
    • 1970-01-01
    • 2021-02-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多