如何用localStorage/Cookie持久化保存复选框状态与待办列表数据
待办列表本地持久化实现方案
直接选localStorage实现即可,相比Cookie它容量更大、不会随接口请求额外携带数据,完全满足前端持久化需求,不需要额外封装类,按下面的逻辑拆分就能跑通:
- 拆分两个存储键:
todo_username存用户输入的姓名,todo_tasks存所有待办任务的结构化数据(任务内容、复选框选中状态) - 页面加载时优先读取本地存储数据:如果已有用户名就跳过输入弹窗,已有任务数据直接渲染到页面
- 抽离单条任务的渲染逻辑,新增任务、页面初始化渲染复用同一段代码
- 所有任务操作(新增、勾选/取消勾选、删除)完成后,立刻把最新数据同步写入localStorage,保证页面重载后数据不丢失
修改后完整代码
JavaScript 代码
const tasksContainer = document.querySelector(".tasks"); const helloBlock = document.querySelector(".helloUser"); const typingElem = document.querySelector(".todotext"); const taskInput = document.querySelector(".inputTasks"); const typingText = "ToDoList!"; const typingDelay = 100; // 打字机效果,原有逻辑保留 function printText(text, elem, delay) { if (text.length > 0) { elem.innerHTML += text[0]; setTimeout(() => { printText(text.slice(1), elem, delay); }, delay); } } // 从DOM收集最新任务数据,同步到localStorage function syncTasksToStorage() { const allTasks = []; document.querySelectorAll(".task").forEach(taskEl => { allTasks.push({ content: taskEl.querySelector(".taskName").textContent, completed: taskEl.querySelector(".checkBox").checked }); }); localStorage.setItem("todo_tasks", JSON.stringify(allTasks)); } // 渲染单条任务 function renderSingleTask(taskContent, isCompleted = false) { const divTask = document.createElement("div"); divTask.className = "task"; const checkBox = document.createElement("input"); checkBox.type = "checkbox"; checkBox.className = "checkBox"; checkBox.checked = isCompleted; const trashBtn = document.createElement("div"); trashBtn.className = "trash"; trashBtn.innerHTML = "🗑️"; const taskText = document.createElement("div"); taskText.className = "taskName"; taskText.innerHTML = taskContent; if (isCompleted) taskText.classList.add("complete"); divTask.appendChild(checkBox); divTask.appendChild(taskText); divTask.appendChild(trashBtn); tasksContainer.appendChild(divTask); // 复选框切换事件 checkBox.addEventListener('change', () => { taskText.classList.toggle("complete", checkBox.checked); syncTasksToStorage(); }); // 删除任务事件 trashBtn.addEventListener('click', () => { if (confirm(`你确定要删除任务:${taskContent} 吗?`)) { divTask.remove(); syncTasksToStorage(); } }); } document.body.onload = () => { // 读取存储的用户名,没有才弹窗询问 let userName = localStorage.getItem("todo_username"); if (!userName) { userName = prompt("你好!我该怎么称呼你?"); localStorage.setItem("todo_username", userName); } helloBlock.innerHTML = `你好 ${userName}!这是你的待办清单,也就是现在大家常说的个人专属 `; // 启动打字机效果 printText(typingText, typingElem, typingDelay); setInterval(() => { typingElem.innerHTML = ""; printText(typingText, typingElem, typingDelay); }, 4000); // 渲染存储的已有任务 const savedTasks = JSON.parse(localStorage.getItem("todo_tasks") || "[]"); savedTasks.forEach(task => renderSingleTask(task.content, task.completed)); // 回车新增任务 taskInput.onkeypress = (event) => { const taskStr = taskInput.value.trim(); if (event.keyCode === 13) { if (!taskStr) { alert("你没有输入任何任务内容"); return; } renderSingleTask(taskStr); taskInput.value = ""; syncTasksToStorage(); } } }
HTML 代码(和原有代码完全一致,无需修改)
<body> <div class="container"> <div class="helloUser"></div> <div class="todotext"></div> <input type="text" class="inputTasks" placeholder="输入任务"> <div class="tasks"></div> <script src="js/script.js"></script> </div> </body>
实现说明
- 代码里已经把原俄文提示全部翻译成中文,如果需要保留俄文直接替换对应提示文本即可
- 存储逻辑加了空值兜底,第一次打开页面没有存储数据时不会报错
- 每次DOM更新后才同步数据到存储,保证存储数据和页面展示完全一致,不会出现状态不同步的问题
- 如果后续需要清空所有数据,直接调用
localStorage.clear()即可,也可以自己加个清空按钮绑定这个方法
内容的提问来源于stack exchange,提问作者Dread
相关产品推荐
相关产品推荐

