如何实现待办应用已完成、编辑任务的localStorage本地存储?
待办应用功能补全方案
你现有代码的核心问题有4个:
- 任务数据没存「完成状态」字段,刷新后完成状态必然丢失
- 编辑、标记完成操作只改了页面显示效果,没更新内存里的
taskList数组,自然没法同步到localStorage - 删除逻辑有bug:
indexOf直接查找id字符串,但数组里存的是任务对象,永远返回-1,会出现删错内容的问题 - 渲染模板没闭合div标签,DOM结构错乱,而且刷新后不会自动给已完成任务加删除线样式
按下面步骤修改即可:
1. 补全任务数据结构,修复删除逻辑bug
首先给每个任务加默认的未完成标记,修正删除时的索引查找逻辑:
// 新建任务时增加isCompleted字段 function makeNewTask() { const data = { id: createId(), taskNew: el.input.value.trim(), taskDate: el.date.value, taskTime: el.time.value, isCompleted: false // 新任务默认标记为未完成 }; return data; } // 修复删除逻辑 function deleteItem(event) { const taskId = event.target.dataset.id; // 按id精准定位对应任务的索引 const targetIndex = taskList.findIndex(item => item.id === taskId); if(targetIndex > -1) taskList.splice(targetIndex, 1); storeList(); renderList(); }
2. 修改渲染逻辑,自动同步状态样式
修改renderList函数,补全缺失的标签闭合,根据任务完成状态自动加删除线,同时让完成按钮的文字根据状态切换为「完成/撤销完成」:
function renderList() { el.list.innerHTML = taskList.map(function (data) { // 已完成任务自动添加删除线样式 const lineStyle = data.isCompleted ? 'text-decoration: line-through;' : ''; return `<div class="task"> <div class="task-content"> <div class="task" data-id="${data.id}"> <input class="new-task-created" value="${data.taskNew}" readonly style="${lineStyle}"> <input class="due-date" type="date" value="${data.taskDate}" readonly style="${lineStyle}"> <input class="due-time" type="time" value="${data.taskTime}" readonly style="${lineStyle}"> </div> <div class="action-buttons"> <button onclick="editItem(event)" class="edit" data-id="${data.id}">Edit</button> <button onclick="deleteItem(event)" class="delete" data-id="${data.id}">Delete</button> <button onclick="completeItem(event)" class="complete" data-id="${data.id}">${data.isCompleted ? 'Undo' : 'Complete'}</button> </div> </div> </div>`; // 补全原来缺失的闭合标签 }).join('') // 去掉数组转字符串时自动生成的多余逗号 // 提交后清空所有输入框 el.input.value = ""; el.date.value = ""; el.time.value = ""; }
3. 实现编辑功能的本地存储同步
修改editItem函数,点击Save保存时,把输入的新内容更新到taskList对应项,再同步存储到localStorage:
function editItem(event) { const editBtn = event.target; const taskId = editBtn.dataset.id; const editEl = editBtn.closest(".task"); const taskInput = editEl.querySelector(".new-task-created"); const dateInput = editEl.querySelector(".due-date"); const timeInput = editEl.querySelector(".due-time"); if (editBtn.innerHTML.toLowerCase() === "edit"){ taskInput.removeAttribute("readonly"); dateInput.removeAttribute("readonly"); timeInput.removeAttribute("readonly"); taskInput.focus(); editBtn.innerHTML = "Save"; } else { // 定位要更新的任务条目 const targetTask = taskList.find(item => item.id === taskId); if(targetTask) { // 更新内存中的任务数据 targetTask.taskNew = taskInput.value.trim(); targetTask.taskDate = dateInput.value; targetTask.taskTime = timeInput.value; // 同步到localStorage storeList(); } taskInput.setAttribute("readonly", "readonly"); dateInput.setAttribute("readonly", "readonly"); timeInput.setAttribute("readonly", "readonly"); editBtn.innerHTML = "Edit"; // 重新渲染保证数据和页面显示一致 renderList(); } }
4. 实现标记完成的本地存储同步
修改completeItem函数,点击按钮时切换任务的完成状态,同步存储到localStorage:
function completeItem(event) { const completeBtn = event.target; const taskId = completeBtn.dataset.id; const targetTask = taskList.find(item => item.id === taskId); if(targetTask) { // 切换完成/未完成状态 targetTask.isCompleted = !targetTask.isCompleted; // 同步到localStorage storeList(); // 重新渲染自动更新样式 renderList(); } }
已完成任务分栏实现(可选)
如果要把未完成、已完成任务分开显示,先修改HTML添加两个列表容器:
<h3>待完成</h3> <div class="list pending-list"></div> <h3>已完成</h3> <div class="list completed-list"></div>
然后修改JS里的元素选择器,把原来的list拆成两个:
const el = { form: document.querySelector(".form"), input: document.querySelector(".user-input"), pendingList: document.querySelector(".pending-list"), completedList: document.querySelector(".completed-list"), date: document.querySelector(".date"), time: document.querySelector(".time"), };
最后修改renderList,分别渲染两类任务,可以抽离模板减少重复代码:
// 抽离单条任务的渲染模板 function getTaskTemplate(data) { const lineStyle = data.isCompleted ? 'text-decoration: line-through;' : ''; return `<div class="task"> <div class="task-content"> <div class="task" data-id="${data.id}"> <input class="new-task-created" value="${data.taskNew}" readonly style="${lineStyle}"> <input class="due-date" type="date" value="${data.taskDate}" readonly style="${lineStyle}"> <input class="due-time" type="time" value="${data.taskTime}" readonly style="${lineStyle}"> </div> <div class="action-buttons"> <button onclick="editItem(event)" class="edit" data-id="${data.id}">Edit</button> <button onclick="deleteItem(event)" class="delete" data-id="${data.id}">Delete</button> <button onclick="completeItem(event)" class="complete" data-id="${data.id}">${data.isCompleted ? 'Undo' : 'Complete'}</button> </div> </div> </div>`; } function renderList() { // 拆分未完成、已完成任务 const pendingTasks = taskList.filter(item => !item.isCompleted); const completedTasks = taskList.filter(item => item.isCompleted); // 分别渲染到对应容器 el.pendingList.innerHTML = pendingTasks.map(getTaskTemplate).join(''); el.completedList.innerHTML = completedTasks.map(getTaskTemplate).join(''); // 清空输入框 el.input.value = ""; el.date.value = ""; el.time.value = ""; }
内容的提问来源于stack exchange,提问作者Sheldon
相关产品推荐
相关产品推荐

