onClick 方法适用于第二次点击。但它应该在第一次点击时起作用

onClick method works on 2nd click. But it should work on the 1st click

要删除需要在点击deleteButton的时候删除。但是,第一次需要点击2次。我需要做什么才能让它一键生效?

HTML:

    <div class="todo">
    <input id="input" type="text" maxlength="30" placeholder="text...">
    <button id="buttonAdd"><i class="fas fa-pen pencil"></i></button>
    <div id="todoMissions">   </div>
    </div>

JavaScript:

    const todoAdd = document.getElementById("buttonAdd");
    const todoDelete1 = document.getElementsByClassName("buttonDelete");

//ADD
todoAdd.addEventListener("click", () => {
  var p = document.createElement("p");
  var inputValue = document.getElementById("input").value;
  var t = document.createTextNode(inputValue);
  p.appendChild(t);
  p.setAttribute("class" , "mission");

  var html = `${inputValue} <button onclick="todoDelete()" class="buttonDelete"><i class="fas fa-trash trash"></i>`;
  p.innerHTML = html;

  if(inputValue == ""){
      alert("You must write something!");
  }
  else{
      document.getElementById("todoMissions").appendChild(p);
  }
  document.getElementById("input").value = "";
});


//DELETE
function todoDelete(){
  var close = document.getElementsByClassName("buttonDelete");
  for (var i = 0; i < close.length; i++) {
    close[i].onclick = function(){
      var div = this.parentElement;
      div.remove("mission");
    }
  }
}

您的 todoDelete() 函数仅在创建待办事项后调用,并且在该函数内找到所有项目并为其提供 delete 事件处理程序。因此,第一次单击会提供您刚刚单击其处理程序的元素,第二次单击允许该处理程序 运行,删除该元素。

相反,应该在创建元素之前设置处理程序。这可以通过 "event delegation" 来完成,由此您可以在所有元素的祖先上设置处理程序,并允许事件冒泡到要在那里处理的那个元素。由于该元素从一开始就存在,因此在其上设置它没有问题。然后,当稍后动态添加的元素触发事件时,事件冒泡到祖先,在那里处理,并在处理程序中确定事件的实际来源。如果它是正确的来源,那么你就会采取适当的行动。如果没有,什么也不做。这种方法不仅允许动态添加或删除的元素立即参与事件处理,而且它导致仅注册一个事件处理程序,而不是为每个动态添加的元素注册一个,这样更有效且更易于跟踪。

另外:

  • Don't use inline HTML event attributes like onXyz第一个 地点 (here's even more on that).
  • Don't use .getElementsByClassName(),改为使用 .querySelectorAll() 当需要节点 list/collection 时。

所以这里又是你的代码,使用这种方法(参见内嵌的附加评论):

const todoAdd = document.getElementById("buttonAdd");
const output = document.getElementById("todoMissions");

// When you are going to need to use the same element
// over and over, just get the reference just once and
// keep using it.
const input = document.getElementById("input");

// Set up the delete handler on an ancestor of all the potential items
document.querySelector(".todo").addEventListener("click", todoDelete);
    
//ADD
todoAdd.addEventListener("click", () => {
  // Best to test this first and then only do the work if there is a value.
  if(input.value == ""){
      alert("You must write something!");
  }else{
  
    var p = document.createElement("p");
    // Use the .classList API when setting/removing/toggling
    // classes instead of .setAttribute as the API is more straight-forward
    p.classList.add("mission");
  
    // No need to create a text node and then inject that into your string
    // just inject the string value right into the string.
    p.innerHTML = `${input.value} <button class="buttonDelete"><i class="fas fa-trash trash">X</i>`;  
    output.appendChild(p);
  }
  
  input.value = "";
});
    
    
//DELETE
function todoDelete(event){
  // Look at the event argument and see if the event
  // was triggered by a todo item delete button or the
  // <i> element within one.
  if(event.target.classList.contains("buttonDelete") 
    || event.target.classList.contains("trash")){
    event.target.closest("p").remove();  // Remove the nearest ancestor p
  }
}
<div class="todo">
    <input id="input" type="text" maxlength="30" placeholder="text...">
    <button id="buttonAdd"><i class="fas fa-pen pencil">Add</i></button>
    <div id="todoMissions"></div>
</div>

我希望这对您有所帮助,因为您已经得到了答案。所以从技术上讲,您的第一次点击只会创建删除您的元素的事件,这就是为什么它只适用于您的第二次点击。所以我可能只是把 (this) 作为你的 todoDelete

的参数
 var html = `${inputValue} <button onclick="todoDelete(this)" class="buttonDelete">DELETE<i class="fas fa-trash trash"></i>`;

p.innerHTML = HTML;

并将您的删除功能更改为:

function todoDelete(e){
   e.parentNode.remove();
}

const todoAdd = document.getElementById("buttonAdd");
const todoDelete1 = document.getElementsByClassName("buttonDelete");

//ADD
todoAdd.addEventListener("click", () => {
  var p = document.createElement("p");
  var inputValue = document.getElementById("input").value;
  var t = document.createTextNode(inputValue);
  p.appendChild(t);
  p.setAttribute("class" , "mission");
  //by adding (this) as your parameter will help tell the function what element are you on it
  var html = `${inputValue} <button onclick="todoDelete(this)" class="buttonDelete">DELETE<i class="fas fa-trash trash"></i>`;
  p.innerHTML = html;

  if(inputValue == ""){
      alert("You must write something!");
  }
  else{
      document.getElementById("todoMissions").appendChild(p);
  }
  document.getElementById("input").value = "";
});


//DELETE
function todoDelete(e){
  // just removing the parent node of the element
  e.parentNode.remove();
}
<div class="todo">
    <input id="input" type="text" maxlength="30" placeholder="text...">
    <button id="buttonAdd">ADD<i class="fas fa-pen pencil"></i></button>
    <div id="todoMissions"></div>
</div>