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>
要删除需要在点击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>