如何将本地存储用于待办事项列表?

时间:2020-06-21 05:52:05

标签: javascript json local-storage

有人要求我提供一份待办事项清单,并通过本地存储保存每个任务(用户提供的以及原始任务)。我的老师对完全不同的内容做了一个非常简单的演示,我花了几个小时试图弄清楚。当我看解决方案时,老实说我无法弄清楚。看起来真的很复杂,我什至不知道从哪里开始。如果有人可以给我任何提示,那就太好了!

我的代码:

<ace-editor #editor></<ace-editor>

我老师的代码/本地存储解决方案:

let ul = document.querySelector('ul');

let newItem = document.querySelector('input[type=text]');
let checkbox = document.createElement('input');
checkbox.setAttribute('type', 'checkbox');

function output() {
    let newTodo = document.createElement('li');
    newTodo.innerText = newItem.value;
    newTodo.classList.add('todo');
    let ulAppend = ul.append(newTodo);
    ul.append(newTodo);
    let checkboxAppend = newTodo.append(checkbox);
    newTodo.append(checkbox);
    newItem.value = '';
}

let button = document.querySelector('.btn');
button.addEventListener('click', output);

ul.addEventListener('click', function(e) {
    if (e.target.tagName === 'LI') {
        e.target.remove();
    } else if (e.target.tagName === 'INPUT') {
        e.target.parentElement.classList.toggle('finished');
    }
});

即使我的代码更简单(至少从我的判断中也可以看出),它的工作方式与他的代码完全一样。

3 个答案:

答案 0 :(得分:0)

本地存储将JSON对象保存到用户的计算机。您应该创建一个待办事项数组,将该数组添加到每个新的待办事项中,然后将该项目设置为本地存储。

{'Ith': {'users': '490', 'accounts': '1022'}, 'Ban': {'users': '418', 'accounts': '817'}, 'Standard': {'users': '76', 'accounts': '191'}, 'Al': {'users': '85', 'accounts': '145'}, 'Bah': {'users': '58', 'accounts': '94'}, 'National': {'users': '71', 'accounts': '90'}, 'Ahli': {'users': '68', 'accounts': '88'}, 'Khal': {'users': '32', 'accounts': '54'}, 'Kuw': {'users': '3', 'accounts': '7'}, 'State': {'users': '1', 'accounts': '1'}, 'Credit': {'users': '0', 'accounts': '0'}}

答案 1 :(得分:0)

重要的部分在于对数据进行反序列化。这意味着:

  • localStorageJSON.parse(localStorage.getItem("todos")) || [])开始阅读

    我们添加默认的[],因为如果不存在todos键,我们将获得null,并且期望有 list

  • 保存到localStoragelocalStorage.setItem("todos", JSON.stringify(savedTodos))

我们需要JSON.parse及其互补操作JSON.stringify来解析和保存字符串,因为localStorage只能存储字符串。

在您的情况下,您需要从localStorage中读取数据并渲染初始列表。再次将其保存到localStorage,您必须序列化数据。请参见下面的代码片段(链接到有效的JSFIDDLE,因为下面的示例在StackOverflow沙箱环境中不起作用):

let ul = document.querySelector('ul');

let newItem = document.querySelector('input[type=text]');

const Store = {
  serialize () {
    return [].slice.call(document.querySelectorAll("li")).map(c => {
      return {
        text: c.textContent,
        finished: c.querySelector("input").checked
      }
    })
  },
  get () {
    return JSON.parse(localStorage.getItem("todos")) || []
  },
  save () {
    return localStorage.setItem("todos", JSON.stringify(Store.serialize()))
  }
}

const firstItems = Store.get()
firstItems.forEach(it => {
  output(it.text, it.finished)
})

function output(v, finished) {
  let newTodo = document.createElement('li');
  newTodo.innerText = v || newItem.value;
  newTodo.classList.add('todo');
  let ulAppend = ul.append(newTodo);
  ul.append(newTodo);

  // Create a checkbox for each item
  let checkbox = document.createElement('input');
  if (finished) {
    checkbox.checked = true
  }
  checkbox.setAttribute('type', 'checkbox');

  let checkboxAppend = newTodo.append(checkbox);
  newTodo.append(checkbox);
  newItem.value = '';
}

let button = document.querySelector('.btn');
button.addEventListener('click', () => {
    output()
  Store.save()
});

ul.addEventListener('click', function(e) {
  if (e.target.tagName === 'LI') {
    e.target.remove();
  } else if (e.target.tagName === 'INPUT') {
    e.target.parentElement.classList.toggle('finished');
  }
  // Update the value in localStorage when you delete or add a new item
  Store.save()
});
<ul></ul>
<input type="text" /> <button class="btn">Submit</button>

我添加了Store变量,以简化在localStorage中获取和设置数据的方式。

serialize方法将从列表中读取TODO。 document.querySelectorAll("li")返回NodeList,但是通过执行[].slice.call(...),我们将其转换为Array

答案 2 :(得分:0)

我已经为您发布的解决方案添加了注释,以帮助您逐步完成。

// Retrieve elements and store them in variables
const todoForm = document.getElementById("newTodoForm");
const todoList = document.getElementById("todoList");

// Get data stored in localStorage under the key "todos".
// The data type will be a string (local storage can only store strings).
// JSON is a global object that contains methods for working with data represented as strings.
// The `||` syntax is an OR operator and is used here to set an empty array as a fallback in case `localStorage` is empty
const savedTodos = JSON.parse(localStorage.getItem("todos")) || [];

// Create a loop the same length as the list of todos
for (let i = 0; i < savedTodos.length; i++) {
  // Create an <li> element in memory (does not appear in the document yet)
  let newTodo = document.createElement("li");
  // Set the inner text of that new li with the contents from local storage.
  // The savedTodos[i] is accessing data in the localStorage array.
  // The [i] is a different number each loop.
  // The `.task` is accessing 'task' property on the object in the array.
  newTodo.innerText = savedTodos[i].task;
  // Create a new property on the element called `isCompleted` and assign a boolean value.
  // This is only accessible in code and will not show up when appending to the DOM.
  newTodo.isCompleted = savedTodos[i].isCompleted ? true : false;
  // Check the value we just set.
  if (newTodo.isCompleted) {
    // Create a style for the element if it is done (strike it out)
    newTodo.style.textDecoration = "line-through";
  }
  // Actually append the new element to the document (this will make it visible)
  todoList.appendChild(newTodo);
}

// `addEventListener` is a function that registers some actions to take when an event occurs.
// The following tells the browser - whenever a form is submitted, run this function.
todoForm.addEventListener("submit", function(event) {
  // Don't try to send the form data to a server. Stops page reloading.
  event.preventDefault();
  // Create a <li> element in memory (not yet visible in the document)
  let newTodo = document.createElement("li");
  // Find element in the document (probably a input element?) and access the text value.
  let taskValue = document.getElementById("task").value;
  // Set the text of the <li>
  newTodo.innerText = taskValue;
  // Set a property on the <li> call `isCompleted`
  newTodo.isCompleted = false;
  // Empty out all the input fields in the form
  todoForm.reset();
  // Make the new <li> visible in the document by attaching it to the list
  todoList.appendChild(newTodo);

  // `push` adds a new element to the `savedTodos` array. In this case, an object with 2 properties.
  savedTodos.push({ task: newTodo.innerText, isCompleted: false });
  // Overwrite the `todos` key in local storage with the updated array.
  // Use the JSON global object to turn an array into a string version of the data
  // eg [1,2,3] becomes "[1,2,3]"
  localStorage.setItem("todos", JSON.stringify(savedTodos));
});

// This tells the browser - whenever the todoList is clicked, run this function.
// The browser will call the your function with an object that has data about the event.
todoList.addEventListener("click", function(event) {
  // the `target` of the event is the element that was clicked.
  let clickedListItem = event.target;

  // If that element has a property called `isCompleted` set to true
  if (!clickedListItem.isCompleted) {
    // update the styles and toggle the `isCompleted` property.
    clickedListItem.style.textDecoration = "line-through";
    clickedListItem.isCompleted = true;
  } else {
    clickedListItem.style.textDecoration = "none";
    clickedListItem.isCompleted = false;
  }

  // The code above changes the documents version of the data (the elements themselves)
  // This loop ensures that the array of todos data is kept in sync with the document
  // Loop over the array
  for (let i = 0; i < savedTodos.length; i++) {
    // if the item in the array has the same text as the item just clicked...
    if (savedTodos[i].task === clickedListItem.innerText) {
      // toggle the completed state
      savedTodos[i].isCompleted = clickedListItem.isCompleted;
      // Update the localStorage with the new todos array.
      localStorage.setItem("todos", JSON.stringify(savedTodos));
    }
  }
});

请记住,待办事项列表中有2个状态源。一个是文档的外观,另一个是todos数据的数组。确保这两个保持同步会带来很多挑战。

如果文档不知何故显示其中一个列表项被划掉,但是您的数据数组显示所有todos都未完成,哪个版本正确?这里没有正确的答案,但是在将来设计应用程序时,您可能会考虑使用状态管理。 Redux是一个很好的js库,具有易于理解的模式,可以帮助解决此问题。希望最后的评论不要混淆太多。祝你好运!