简体   繁体   English

如何让我的 JavaScript 删除函数多次触发?

[英]How can I get my JavaScript delete function to fire more than once?

I'm building a todo app and I use a function to create a list item entered by the user.我正在构建一个待办事项应用程序,并使用一个函数来创建用户输入的列表项。

There is an event listener added to the output section to listen for a delete button click for each item displayed.输出部分添加了一个事件侦听器,用于侦听显示的每个项目的删除按钮单击。 My problem is that the delete button is only working for one item and then it stops working.我的问题是删除按钮仅适用于一项,然后停止工作。

In the console, it appears that the function is actually called every time I press the button, but the functionality only works for one click.在控制台中,似乎每次按下按钮时实际上都会调用该函数,但该功能仅适用于单击一次。 Do I need to add all the list items into an array perhaps?我是否需要将所有列表项添加到数组中?

 const todo = document.getElementById('todo'); const enter = document.getElementById('enter'); const output = document.getElementById('output'); enter.addEventListener('click', () => { listItem(todo); }); let createListItem; var deleteBtn; let checkBtn; function listItem(todo) { createListItem = document.createElement('li'); createListItem.innerText = todo.value; todo.value = ''; output.appendChild(createListItem); checkBtn = document.createElement('button'); deleteBtn = document.createElement('button'); checkBtn.innerText = 'check'; deleteBtn.innerText = 'delete'; createListItem.append(checkBtn); createListItem.append(deleteBtn); checkBtn.classList.add('checkBtn'); deleteBtn.classList.add('deleteBtn'); } output.addEventListener('click', deleteFunc); function deleteFunc() { console.log('function called'); createListItem.remove(); }
 <section class="controls"> <div> <label for="todo">Enter a to-do</label> <input type="text" name="todo" id="todo"> </div> <span> <button id="enter" class = "enter"><i class="fas fa-paper-plane"></i></button> </span> </section> <section> <ul id="output" class="output"> </ul> </section>

You need to delegate and use relative addressing because your code only removes the LAST added LI您需要委托和使用相对寻址,因为您的代码只删除了最后添加的 LI

The variable createListItem pollutes the global scope.变量createListItem污染全局范围。 Add the keyword var or let in the listItem function too在 listItem 函数中也添加关键字varlet

function deleteFunc(e) {
  console.log('function called');
  const tgt = e.target;
  if (e.target.innerText==="delete") tgt.closest("li").remove()
}

Added benefit from this delegation is that adding the functionality to the "check" button is just这种委托的额外好处是将功能添加到“检查”按钮只是

  if (e.target.innerText==="check") ...

I would recommend to use a class and testing我建议使用类和测试

if (e.target.classList.contains("delete") 

instead of the innerText - especially if you want to change language of the button而不是innerText - 特别是如果你想改变按钮的语言

 const todo = document.getElementById('todo'); const enter = document.getElementById('enter'); const output = document.getElementById('output'); enter.addEventListener('click', () => { listItem(todo); }); let createListItem; var deleteBtn; let checkBtn; function listItem(todo) { let createListItem = document.createElement('li'); // use let or var here createListItem.innerText = todo.value; todo.value = ''; output.appendChild(createListItem); checkBtn = document.createElement('button'); deleteBtn = document.createElement('button'); checkBtn.innerText = 'check'; deleteBtn.innerText = 'delete'; createListItem.append(checkBtn); createListItem.append(deleteBtn); checkBtn.classList.add('checkBtn'); deleteBtn.classList.add('deleteBtn'); } output.addEventListener('click', deleteFunc); function deleteFunc(e) { console.log('function called'); const tgt = e.target; if (e.target.innerText==="delete") tgt.closest("li").remove() }
 <section class="controls"> <div> <label for="todo">Enter a to-do</label> <input type="text" name="todo" id="todo"> </div> <span> <button id="enter" class = "enter"><i class="fas fa-paper-plane"></i></button> </span> </section> <section> <ul id="output" class="output"> </ul> </section>

Your createListItem variable is a global that gets set to the most-recently appended item, so the delete function will always delete the most-recent item.您的createListItem变量是一个全局变量,它被设置为最近追加的项目,因此删除函数将始终删除最近的项目。 Once an element el has already been removed from the DOM tree, el.remove() is a no-op, so it only works once.一旦元素el已经从 DOM 树中删除, el.remove()是一个空操作,所以它只能工作一次。

To fix, you can either use event delegation as in @mplungjan's answer or assign a unique id to each list item and pass that as a parameter to the function to determine what to delete.要修复,您可以使用@mplungjan 的答案中的事件委托,也可以为每个列表项分配一个唯一的 id,并将其作为参数传递给函数以确定要删除的内容。

Example of the second approach:第二种方法的例子:

<ul>
  <li id="item-0"></li>
  <li id="item-1"></li>
  <li id="item-2"></li>
</ul>
const deleteById = id => document.querySelector(`#item-${id}`).remove()

First though:不过首先:

I think os because you are targeting the "ul" instead the "li" elements.我认为 os 是因为您的目标是“ul”而不是“li”元素。 Try adding the event listeners to each "li" element with a querySelectorAll() instead of targeting "output" directly.尝试使用 querySelectorAll() 将事件侦听器添加到每个“li”元素,而不是直接定位“输出”。

When you add another item, you call listItem() which sets a new value to createListItem .当您添加另一个项目时,您调用listItem()createListItem设置一个新值。 This means, when you call deleteFunc() , createListItem.remove();这意味着,当您调用deleteFunc()deleteFunc() createListItem.remove(); is only executed on the last element you have added.仅在您添加的最后一个元素上执行。 If this item was already removed, your out of luck as well.如果此项目已被删除,那么您也不走运。

function deleteFunc(e) {
  console.log('function called');
  const { target } = e; // get target
  target.closest("li").remove()
}

Remove the listener on output .删除output上的侦听器。 (This line: output.addEventListener('click', deleteFunc); ) (这一行: output.addEventListener('click', deleteFunc);

And add the listener to each deleteBtn :并将侦听器添加到每个deleteBtn

checkBtn.classList.add('checkBtn');
deleteBtn.classList.add('deleteBtn');
deleteBtn.addEventListener('click', deleteFunc);

This might help you: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest这可能对您有所帮助: https : //developer.mozilla.org/en-US/docs/Web/API/Element/closest

Find the solution.找到解决办法。

 const todo = document.getElementById('todo'); const enter = document.getElementById('enter'); const output = document.getElementById('output'); enter.addEventListener('click', () => { listItem(todo); }); let createListItem; var deleteBtn; let checkBtn; var index = 0; function listItem(todo) { createListItem = document.createElement('li'); createListItem.innerText = todo.value; createListItem.id= 'li' + index; todo.value = ''; output.appendChild(createListItem); checkBtn = document.createElement('button'); deleteBtn = document.createElement('button'); checkBtn.innerText = 'check'; deleteBtn.innerText = 'delete'; deleteBtn.id = 'btn' + index; createListItem.append(checkBtn); createListItem.append(deleteBtn); checkBtn.classList.add('checkBtn'); deleteBtn.classList.add('deleteBtn'); deleteBtn.onclick = function() { deleteFunc(this); }; index += 1; } //output.addEventListener('click', deleteFunc); function deleteFunc(e) { var rowId = e.id.replace('btn',''); var row = document.getElementById('li'+rowId); console.log('function called' + rowId); //alert(rowId); if (row != null) { row.remove(); } //console.log('function called'); //createListItem.remove(); }
 <section class="controls"> <div> <label for="todo">Enter a to-do</label> <input type="text" name="todo" id="todo"> </div> <span> <button id="enter" class = "enter"><i class="fas fa-paper-plane"></i></button> </span> </section> <section> <ul id="output" class="output"> </ul> </section>

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

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