JavaScript-1. .splice()行为怪异2. .classList.add行为怪异

时间:2020-05-23 11:22:15

标签: javascript

我正在使用香草JavaScript开发“待办事项列表”应用。目前我有两个问题。

  1. 当我从列表底部删除项目时,删除功能可以正常工作。但是,如果我从顶部删除,它将首先从底部删除该项目,然后是第二个,最后是顶部。如何解决此问题,以便删除我刚点击的那个?

  2. 如果单击“检查”按钮,则该任务应标记为已完成,并且“ completed”类将添加到html中。但是,如果我单击“检查”按钮,则在数据结构中,似乎已成功切换“ isCompleted”的值,但将立即从html中删除类,例如0.01秒后。

有什么问题,我该如何解决?

const todoBlock = document.querySelector(".task__nav");
const submitForm = document.querySelector(".form");
const taskItem = document.querySelector(".task");

const taskContainer = document.querySelector(".todo__container");

const showAllTasksNav = document.querySelector(".task__nav-item.all");
const showCompletedTasksNav = document.querySelector(
  ".task__nav-item.finished"
);

const taskContainer_new = document.querySelector(".items");

let todoList = [];
todoList = JSON.parse(localStorage.getItem("todolist")) || [];
updateUI();

submitForm.addEventListener("submit", event => {
  event.preventDefault();
  if (taskItem.value !== "") {
    addTodo(taskItem.value);
  }
});

function addTodo(task) {
  const todo = {
    task: taskItem.value,
    isCompleted: false,
    id: Date.now()
  };

  todoList.push(todo);

  updateUI();
  clearInput();
}

function updateUI() {
  taskContainer_new.textContent = "";

  todoList.forEach(el => {
    showItems(el.id, el.task);
  });
  localStorage.setItem("todolist", JSON.stringify(todoList));
}

function showItems(id, task) {
  const markup = `
  <div class="todo__item" data-key=${id}>
  <p>${task}</p>
  <div class="icons">
  <button class="item__complete--btn"><svg class="ion-ios-checkmark-outline" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="1em" height="1em" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 512 512"><path d="M340.1 177.3L215.3 303l-47.2-47.2-17.8 17.8 56 56c2.5 2.5 5.9 4.5 8.9 4.5s6.3-2 8.8-4.4l133.7-134.4-17.6-18z" fill="#626262"/><path d="M256 48C141.1 48 48 141.1 48 256s93.1 208 208 208 208-93.1 208-208S370.9 48 256 48zm0 398.7c-105.1 0-190.7-85.5-190.7-190.7 0-105.1 85.5-190.7 190.7-190.7 105.1 0 190.7 85.5 190.7 190.7 0 105.1-85.6 190.7-190.7 190.7z" fill="#626262"/></svg></button>
  <button class="item__delete--btn"><svg class="ion-ios-close-outline" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="1em" height="1em" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 512 512"><path d="M403.1 108.9c-81.2-81.2-212.9-81.2-294.2 0s-81.2 212.9 0 294.2c81.2 81.2 212.9 81.2 294.2 0s81.2-213 0-294.2zm-12.3 281.9c-74.3 74.3-195.3 74.3-269.6 0-74.3-74.3-74.3-195.3 0-269.6s195.3-74.3 269.6 0c74.4 74.3 74.4 195.3 0 269.6z" fill="#626262"/><path d="M340.2 160l-84.4 84.2-84-83.8-11.8 11.8 84 83.8-84 83.8 11.8 11.8 84-83.8 84.4 84.2 11.8-11.8-84.4-84.2 84.4-84.2z" fill="#626262"/></svg></button>
  </div>
  </div>
  `;

  taskContainer_new.insertAdjacentHTML("afterbegin", markup);
}

taskContainer.addEventListener("click", event => {
  const target = event.target;

  const id = target.parentNode.parentNode.parentNode.dataset.key;

  if (target.classList.contains("ion-ios-checkmark-outline")) {
    toggleTodo(id);
  } else if (target.classList.contains("ion-ios-close-outline")) {
    deleteTodo(target);
  }
});

function clearInput() {
  taskItem.value = "";
}

function toggleTodo(key) {
  const index = todoList.findIndex(item => item.id === Number(key));
  todoList[index].isCompleted = !todoList[index].isCompleted;

  const item = document.querySelector(`[data-key="${key}"]`);

  if (todoList[index].isCompleted) {
    item.classList.add("completed");
    console.log("class added");
  } else {
    item.classList.remove("completed");
  }
  updateUI();
}

function deleteTodo(target) {
  const targetTaskId = target.parentNode.parentNode.parentNode.dataset.key;
  const index = todoList.findIndex(item => item.id === Number(targetTaskId));

  console.log("todoList[index]", todoList[index]);

  todoList.splice(todoList[index], 1);

  updateUI();
}

showAllTasksNav.addEventListener("click", displayAllTasks);
showCompletedTasksNav.addEventListener("click", displayCompletedTask);

function displayCompletedTask() {
  showAllTasksNav.classList.remove("active");
  showCompletedTasksNav.classList.add("active");

  todoList.filter(function(index, value) {
    return index.isCompleted;
  });
}

function displayAllTasks() {
  showCompletedTasksNav.classList.remove("active");
  showAllTasksNav.classList.add("active");

  updateUI();
}

    <div class="wrapper">
      <h1>To Do List</h1>
      <div class="input__area">
        <form class="form">
          <input class="task" type="text" placeholder="Enter Task" />
          <input class="add" type="submit" value="ADD" />
        </form>
      </div>

      <div class="todo__container">
        <ul class="task__nav">
          <li class="task__nav-item all">All Tasks</li>
          <li class="task__nav-item finished">Completed Tasks</li>
        </ul>
        <div class="items"></div>
      </div>
    </div>
* {
    margin: 0;
    padding: 0;
}
body {
    font-family: 'Roboto', sans-serif;
    background: linear-gradient(to right, #aaffa9, #11ffbd); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
    color: #666;
}
.wrapper {
    width: 80vw;
    height: 80vh;
    margin: 0 auto;
    padding: 20px 0 0 0;
}
h1 {
    color: #fff;
    text-shadow: 2px 2px rgba(0,0,0,0.05);
    text-align: center;
}
button {
    background-color: transparent;
    border: none;
    transition: transform .1s;
    cursor: none;
    outline: none;
}
button i {
    color: #666;
    font-size: 150%;
    padding-left: 10px;
    cursor: pointer;
    outline: none;
}
button:hover {
    transform: scale(1.2);
    cursor: pointer;
}
.task__nav {
    padding: 0;
    margin: 0 0 40px 0;
    list-style: none;
}
.task__nav-item {
    cursor: pointer;
    float: right;
    font-size: 80%;
    margin-left: 20px;
}
.task__nav-item.active {
    /* color: #eb4034; */
    font-weight: bold;
}
.input__area {
    margin: 10px 0 20px 0;
    box-shadow: 2px 0px 2px 0px rgba(0,0,0,0.05);
    width: 100%;
} 
.input__area form {
    display: flex;
    justify-content: space-between;
    width: 100%;
}
.todo__container {
    background: #fff;
    box-shadow: 2px 0px 2px 0px rgba(0,0,0,0.05);
    padding: 20px 20px 30px 20px;
}
input {
    outline: none;
  }
input[type="text"] {
    border: none;
    width: 100%;
    padding: 10px 10px;
    box-sizing: border-box;
}
input[type="text"]::placeholder {
    color: #ccc;
}
input[type="submit"] {
    width: 20%;
    padding: 10px;
    border: none;
    background-color: #ec5757;
    color: #fff;
    font-weight: bold;
}
.todo__item {
    padding: 10px 10px;
    border-bottom: 1px solid #ccc;
    display: flex;
    justify-content: space-between;
    align-items: center;
}
.todo__item.completed p::after {
    margin: 0 0 0 10px;
    content: "Finished!";
    color: #ec5757;
    font-weight: bold;
    font-size: 70%;
}

3 个答案:

答案 0 :(得分:1)

Splice希望索引为第一个参数,第二个参数代表要删除的项目数

array.splice(index, howmany, item1, ....., itemX)

尝试更改todoList.splice(todoList [index],1);到

todoList.splice(index, 1);

对于第二个问题,您不必在类列表中添加或删除“完成的”类,则可以在showItems方法中创建html标记时有条件地进行处理

function showItems(id, task) {
  const completedClassName = todoList.find(e => element.id === id).isCompleted ? 'completed' : '';

   const markup = `
    <div class="todo__item ${completedClassName}" data-key=${id}>
      ... remaining markup
    </div>
  `;
  taskContainer_new.insertAdjacentHTML("afterbegin", markup);
}

答案 1 :(得分:1)

deleteTodo函数中,您可以使用Array.filter方法从todoList数组中删除一项:

function deleteTodo(target) {
  const targetTaskId = target.parentNode.parentNode.parentNode.dataset.key;

  todoList = todoList.filter(function(item) {
    return item.id !== Number(targetTaskId);
  });

  updateUI();
}

关于您的第二个问题,completed类立即被“删除”的原因是,您的showItems函数重新提供了待办事项,而没有考虑到某些项目应具有{在completed属性内添加了{1}}:

class

这是工作代码:

答案 2 :(得分:1)

第一个问题是因为您没有将待删除的待办事项索引传递给splice函数

如下所示更改deleteTodo功能

function deleteTodo(target) {
  const targetTaskId = target.closest('.todo__item').dataset.key;
  const index = todoList.findIndex(item => item.id === Number(targetTaskId));

  todoList.splice(index, 1);

  updateUI();
}

第二个问题是因为您要在todo的容器元素上添加completed类,但之后立即调用updateUI函数,该函数将删除completed课。

如下所示更改toggleTodo功能

function toggleTodo(key) {
  const index = todoList.findIndex(item => item.id === Number(key));
  todoList[index].isCompleted = !todoList[index].isCompleted;

  updateUI();
}

在调用updateUI函数时,您需要传递当前待办事项是否标记为已完成。如果是,则showItems函数应添加completed

您的updateUI函数应更改为

function updateUI() {
  taskContainer_new.textContent = "";

  todoList.forEach(el => {
    showItems(el.id, el.task, el.isCompleted);
  });

  localStorage.setItem("todolist", JSON.stringify(todoList));
}

showItems用作

function showItems(id, task, isCompleted) {
  const markup = `
  <div class="todo__item ${isCompleted ? 'completed' : ''}" data-key=${id}>
  <p>${task}</p>
  <div class="icons">
  <button class="item__complete--btn"><svg class="ion-ios-checkmark-outline" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="1em" height="1em" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 512 512"><path d="M340.1 177.3L215.3 303l-47.2-47.2-17.8 17.8 56 56c2.5 2.5 5.9 4.5 8.9 4.5s6.3-2 8.8-4.4l133.7-134.4-17.6-18z" fill="#626262"/><path d="M256 48C141.1 48 48 141.1 48 256s93.1 208 208 208 208-93.1 208-208S370.9 48 256 48zm0 398.7c-105.1 0-190.7-85.5-190.7-190.7 0-105.1 85.5-190.7 190.7-190.7 105.1 0 190.7 85.5 190.7 190.7 0 105.1-85.6 190.7-190.7 190.7z" fill="#626262"/></svg></button>
  <button class="item__delete--btn"><svg class="ion-ios-close-outline" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="1em" height="1em" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 512 512"><path d="M403.1 108.9c-81.2-81.2-212.9-81.2-294.2 0s-81.2 212.9 0 294.2c81.2 81.2 212.9 81.2 294.2 0s81.2-213 0-294.2zm-12.3 281.9c-74.3 74.3-195.3 74.3-269.6 0-74.3-74.3-74.3-195.3 0-269.6s195.3-74.3 269.6 0c74.4 74.3 74.4 195.3 0 269.6z" fill="#626262"/><path d="M340.2 160l-84.4 84.2-84-83.8-11.8 11.8 84 83.8-84 83.8 11.8 11.8 84-83.8 84.4 84.2 11.8-11.8-84.4-84.2 84.4-84.2z" fill="#626262"/></svg></button>
  </div>
  </div>
  `;

  taskContainer_new.insertAdjacentHTML("afterbegin", markup);
}

这里是working demo,与您的代码不同,它还显示了已完成任务和所有正确任务的列表

相关问题