开发Todo应用时LocalStorage无法保存输入值,仅存储空对象的问题求助
嘿,我看到你遇到的问题了——把Todo项存到LocalStorage时总是生成空对象{}对吧?这其实是个常见的小坑,咱们一步步来搞定它:
问题根源
你现在尝试用JSON.stringify(para)把DOM元素(也就是你创建的<ul>节点)转成JSON,但JSON没法正确序列化DOM元素,所以转出来的结果就是空对象。你真正需要存储的是Todo项的文本内容,而不是DOM节点本身。
修复后的完整代码
HTML(小优化:把Todo容器改成<ul>更符合语义)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Todo App</title> </head> <body> <h2>Todo List</h2> <div id="hello"> <h1>My Todos</h1> </div> <button id="btn">delete</button> <br> <br> <input type="text" id="txt" placeholder="Add a new todo..."> <button type="submit" id="sub">+</button> <!-- 改成ul作为列表容器,语义更规范 --> <ul id="kno"></ul> <script src="main.js"></script> </body> </html>
JavaScript(核心逻辑修改)
// 初始化Todo数组:优先从LocalStorage读取,没有的话设为空数组 let todos = JSON.parse(localStorage.getItem('todos')) || []; const todoContainer = document.getElementById('kno') const inputBox = document.getElementById('txt') // 添加Todo的逻辑 document.getElementById('sub').addEventListener('click',()=>{ const todoText = inputBox.value.trim(); if (!todoText) return; // 空内容不添加,避免无效Todo // 创建单个Todo项的DOM元素(用li,符合列表项语义) const todoItem = document.createElement('li') todoItem.innerText = todoText todoContainer.appendChild(todoItem) inputBox.value = '' // 更新Todo数组并存入LocalStorage todos.push(todoText); localStorage.setItem('todos', JSON.stringify(todos)); // 绑定标记完成事件 bindTodoEvents(todoItem, todoText); }) // 页面加载时,渲染LocalStorage里已存的Todo项 window.addEventListener('load', () => { todos.forEach(todoText => { const todoItem = document.createElement('li') todoItem.innerText = todoText todoContainer.appendChild(todoItem) bindTodoEvents(todoItem, todoText); }) }) // 封装Todo项的事件绑定逻辑,避免重复代码 function bindTodoEvents(todoItem, todoText) { // 单击标记完成(可切换状态) todoItem.addEventListener('click', ()=>{ todoItem.style.textDecoration = todoItem.style.textDecoration === 'line-through' ? 'none' : 'line-through'; // (可选:如果需要保存完成状态,把Todo改成对象存储,比如{text: '买牛奶', completed: false}) }) // 双击删除 todoItem.addEventListener('dblclick', ()=>{ todoContainer.removeChild(todoItem) // 从数组中删除对应项,再更新LocalStorage todos = todos.filter(item => item !== todoText); localStorage.setItem('todos', JSON.stringify(todos)); }) }
关键改进点
- 存储文本而非DOM元素:现在存的是用户输入的文本内容,转JSON完全没问题。
- 用数组存储多个Todo:避免每次添加新Todo覆盖之前的内容。
- 页面加载时自动渲染:刷新页面后之前添加的Todo不会丢失。
- 语义化HTML:把Todo容器改成
<ul>,列表项用<li>,符合HTML规范。 - 封装重复逻辑:把事件绑定抽成函数,减少代码冗余。
如果之后想保存Todo的完成状态,只需要把数组里的字符串改成对象(比如{text: '买牛奶', completed: false}),序列化和反序列化的时候处理一下就行啦~
内容的提问来源于stack exchange,提问作者learner
相关产品推荐
相关产品推荐

