【问题标题】:A Basic Javascript Todo App Acting Weird In ForLoop一个基本的 Javascript Todo 应用程序在 For 循环中表现得很奇怪
【发布时间】:2019-05-05 16:57:41
【问题描述】:

我试图用 HTML、CSS 和 JS 制作我自己的 TODO 应用程序。一切都按预期工作,除了这个奇怪的问题:

当我添加一个待办事项时,forloop 会将 addEventListener 放在它上面,所以当我点击它时,它将启动里面的任何代码

问题:如果我创建了多个待办事项 .. 某些项目停止工作(当我单击该项目时 addEventListener 不工作)。

就像我创建 1 个项目: item1:工作。

如果我创建 2 个项目: 项目1:不工作。 item2:工作。

如果我创建 3 个项目: 项目1:工作。 项目2:不工作。 项目2:工作。 ...ETC。 任何解释如何解决!

HTML 代码

<div id="form">
 <p id="error">Fill The Empty !</p>
<input id="input" type="text" placeholder="Text Here!" >
  <button id="add" type="submit" onclick="addIt()">Add</button>
</div>  
<div id="listContainer">
  <ul id="list">    

  </ul>
  <p id="noItems">You Have No Items!</p>  
</div>

CSS 代码

margin: 0px;
padding: 0px;
font-family: monospace, sans-serif;
list-style: none;
font-size: 10pt;
box-sizing: border-box;
}
#form{
display: flex;
flex-direction: column;
justify-content: center;
align-items:center;
}
#error{
color: red;
display: none;
margin: 5px 0px;
}
#input{
width: 95%;
height: 40px;
text-align: center;
margin: 5px 0px;
border: 1px purple dashed;
}
#add{
height: 40px;
width: 95%;
border: 0px;
color: white;
background-color: purple;
font-weight: 900;
}
#add:active{
color: purple;
background-color: white;
}
#listContainer{
margin-top: 40px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100vw;
}
#list{
display: flex;
flex-direction: column-reverse;
justify-content: center;
align-items: center;
width: 100vw;
}
.item{
position: relative;
text-align: center;
padding: 10px;
margin: 5px;
width: 95%;
color: purple;
background-color: white;
border: 1px purple solid;
font-size: 11pt;
}
.delete{
position: absolute;
right: 0px;
top: 0px;
padding: 10px;
width: 50px;
color: white;
background-color: red;
font-size: 11pt;
font-weight: 900;
}
#noItems{
color: lightgray;
margin-top: 50px;
/*display: none;*/
}

JS 代码

let storeInput = "";

function addIt(){
/*---addIT() start---*/
  let input = document.getElementById("input");
  storeInput = input.value;
  if(storeInput == ""){
    let errorMsg = document.getElementById("error");
    errorMsg.style.display = "block";
    setTimeout(function(){errorMsg.style.display = "none";}, 2000)
  }else{
    input.value = "";
    let item = document.createElement("LI");
    item.className = "item";
    item.innerHTML = storeInput;
    let list = document.getElementById("list");
    list.appendChild(item); 
    let deleteIt = document.createElement("I");
    deleteIt.className = "delete";
    deleteIt.innerHTML = "X";
    item.appendChild(deleteIt);
  }
  let allItems = document.querySelectorAll(".item");
  for(var i = 0; i < allItems.length; i++){
    allItems[i].addEventListener("click", function(){
      if(this.style.textDecoration == "line-through"){
        this.style.textDecoration = "none";
      }else{
        this.style.textDecoration = "line-through";
      }
    })
  }
  let deleteItem = document.querySelectorAll(".delete");
  for(var j = 0; j < deleteItem.length; j++){
    deleteItem[j].addEventListener("click", function(){
      var deleteIt = this.parentElement;
      deleteIt.remove();
    })
  }
  document.querySelectorAll(".item").length;
  if(allItems.length == 0){
    document.getElementById("noItems").style.display = "block";
  }else{
    document.getElementById("noItems").style.display = "none";
  }
/*---addIT() end---*/}

如果您想现场试用该应用: https://codepen.io/Salsa_Project/pen/NVWPaY?editors=0110

和 TY 提前。

【问题讨论】:

    标签: javascript arrays for-loop


    【解决方案1】:

    函数 addit() 为所有项目添加事件监听器,并在每次添加元素时删除按钮。您应该只将事件侦听器添加到当前项目。 codepen

    let storeInput = "";
    
    function addIt(){
    /*---addIT() start---*/
      let input = document.getElementById("input");
      storeInput = input.value;
      if(storeInput == ""){
        let errorMsg = document.getElementById("error");
        errorMsg.style.display = "block";
        setTimeout(function(){errorMsg.style.display = "none";}, 2000)
      }else{
        input.value = "";
        let item = document.createElement("LI");
        item.className = "item";
        item.innerHTML = storeInput;
        let list = document.getElementById("list");
        list.appendChild(item); 
        let deleteIt = document.createElement("I");
        deleteIt.className = "delete";
        deleteIt.innerHTML = "X";
        item.appendChild(deleteIt);
        item.addEventListener("click", function(){
          if(this.style.textDecoration == "line-through"){
            this.style.textDecoration = "none";
          }else{
            this.style.textDecoration = "line-through";
          }
        });
        deleteIt.addEventListener("click", function(){
          var deleteIt = this.parentElement;
          deleteIt.remove();
        })
      }
      let allItems = document.querySelectorAll(".item");
    
    
      document.querySelectorAll(".item").length;
      if(allItems.length == 0){
        document.getElementById("noItems").style.display = "block";
      }else{
        document.getElementById("noItems").style.display = "none";
      }
    /*---addIT() end---*/}
    

    【讨论】:

    • 请在您的答案中添加相关代码,以展示正确答案
    • 编辑器不接受来自笔的代码。唠叨空间之类的
    • 然后链接到 pen/jsfiddle 随便
    • 链接在里面,但如果没有反引号,编辑器不接受它。
    • 哇,现在我完全理解了问题所在..Ty
    【解决方案2】:

    让我们以这个片段为例

      for(var j = 0; j < deleteItem.length; j++){
        deleteItem[j].addEventListener("click", function(){
          var deleteIt = this.parentElement;
          deleteIt.remove();
        })
      }
    

    在这里,您正在运行一个循环,并且 foreach 迭代,您正在创建一个新的点击事件。这里的问题是您没有解除绑定事件。因此,在您当前的代码中,如果您单击按钮,它将触发之前触发的所有调用事件。

    您的代码最快的解决方案是添加类似

    的内容
    let deleteItem = document.querySelectorAll(".delete");
      for(var j = 0; j < deleteItem.length; j++){
         deleteItem[j].parentNode.replaceChild(deleteItem[j].cloneNode(true), deleteItem[j]);
        })
      }
     deleteItem = document.querySelectorAll(".delete");
      for(var j = 0; j < deleteItem.length; j++){
        deleteItem[j].addEventListener("click", function(){
          var deleteIt = this.parentElement;
          deleteIt.remove();
        })
      }
    

    注意

      for(var j = 0; j < deleteItem.length; j++){
         deleteItem[j].parentNode.replaceChild(deleteItem[j].cloneNode(true), deleteItem[j]);
        })
      }
    

    将用它自己替换你当前的元素。唯一的区别是,cloneNode 不会复制事件侦听器。这可以解决您的问题。

    【讨论】:

    • 也有这么详细的解释
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-04
    相关资源
    最近更新 更多