有人要求我提供一份待办事项清单,并通过本地存储保存每个任务(用户提供的以及原始任务)。我的老师对完全不同的内容做了一个非常简单的演示,我花了几个小时试图弄清楚。当我看解决方案时,老实说我无法弄清楚。看起来真的很复杂,我什至不知道从哪里开始。如果有人可以给我任何提示,那就太好了!
我的代码:
<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');
}
});
即使我的代码更简单(至少从我的判断中也可以看出),它的工作方式与他的代码完全一样。
答案 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)
重要的部分在于对数据进行反序列化。这意味着:
从localStorage
(JSON.parse(localStorage.getItem("todos")) || []
)开始阅读
我们添加默认的[]
,因为如果不存在todos
键,我们将获得null
,并且期望有 list
保存到localStorage
(localStorage.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库,具有易于理解的模式,可以帮助解决此问题。希望最后的评论不要混淆太多。祝你好运!