You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

待办列表重复添加且页面刷新后列表不保留问题求助

修复localStorage待办列表的重复渲染与刷新丢失问题

你的代码存在两个核心问题,导致任务重复显示、刷新后列表丢失:

  • 页面加载完成后,没有把localStorage中存储的待办任务渲染到页面
  • 每次提交表单时,遍历整个todos数组重新渲染所有任务,导致旧任务被重复添加

以下是具体修复方案:

关键修复步骤

  • 添加渲染函数:编写统一的函数负责将todos数组内容渲染到页面,页面加载时调用一次,确保刷新后能显示历史任务
  • 移除提交时的全量遍历:提交表单后只需更新数组和localStorage,再调用渲染函数即可,避免重复渲染
  • 修正渲染内容:渲染任务时使用当前todo的content字段,而非固定变量task
  • 完善编辑/删除逻辑:编辑时同步更新数组和localStorage,删除时通过id精准匹配任务

修正后的完整代码

window.addEventListener('load', () => {
    const form = document.querySelector('#new-task-form');
    const input = document.querySelector('#new-task-input');
    const listElement = document.querySelector('#tasks');

    // 从localStorage读取数据,没有则初始化空数组
    let todos = JSON.parse(localStorage.getItem('todos')) || [];

    // 渲染待办列表的函数
    function renderTodos() {
        // 先清空现有列表,避免重复
        listElement.innerHTML = '';
        
        todos.forEach(todo => {
            const taskElement = document.createElement('div');
            taskElement.classList.add('task');

            const taskContentElement = document.createElement('div');
            taskContentElement.classList.add("content");
            taskElement.appendChild(taskContentElement);

            const taskInputElement = document.createElement("input")
            taskInputElement.classList.add("text");
            taskInputElement.type = "text";
            // 使用当前todo的content,而非固定变量
            taskInputElement.value = todo.content;
            taskInputElement.setAttribute('readonly', 'readonly');
            // 给输入框绑定id,方便编辑时找到对应任务
            taskInputElement.dataset.id = todo.id;

            taskContentElement.appendChild(taskInputElement);

            const taskActionsElement = document.createElement('div');
            taskActionsElement.classList.add("actions");

            const taskEditElement = document.createElement('button');
            taskEditElement.classList.add('edit');
            taskEditElement.innerHTML = "Edit";

            const taskDeleteElement = document.createElement('button');
            taskDeleteElement.classList.add('delete');
            taskDeleteElement.innerHTML = "Delete";
            taskDeleteElement.dataset.id = todo.id;

            taskActionsElement.appendChild(taskEditElement);
            taskActionsElement.appendChild(taskDeleteElement);

            taskElement.appendChild(taskActionsElement);
            listElement.appendChild(taskElement);
        });

        // 绑定编辑和删除事件(因为每次渲染后元素是新的,所以要重新绑定)
        bindTaskEvents();
    }

    // 绑定编辑和删除事件的函数
    function bindTaskEvents() {
        // 编辑按钮事件
        document.querySelectorAll('.edit').forEach(btn => {
            btn.addEventListener('click', (e) => {
                const taskInput = e.target.closest('.task').querySelector('.text');
                const todoId = parseInt(taskInput.dataset.id);
                
                if (btn.innerText.toLowerCase() === 'edit') {
                    taskInput.removeAttribute('readonly');
                    taskInput.focus();
                    btn.innerText = "Save";
                } else {
                    taskInput.setAttribute('readonly', 'readonly');
                    btn.innerText = 'Edit';
                    // 更新对应todo的内容
                    todos = todos.map(todo => {
                        if (todo.id === todoId) {
                            return {...todo, content: taskInput.value};
                        }
                        return todo;
                    });
                    localStorage.setItem("todos", JSON.stringify(todos));
                }
            });
        });

        // 删除按钮事件
        document.querySelectorAll('.delete').forEach(btn => {
            btn.addEventListener('click', (e) => {
                const taskElement = e.target.closest('.task');
                const todoId = parseInt(btn.dataset.id);
                // 通过id过滤数组
                todos = todos.filter(todo => todo.id !== todoId);
                localStorage.setItem('todos', JSON.stringify(todos));
                listElement.removeChild(taskElement);
            });
        });
    }

    // 页面加载时先渲染一次列表
    renderTodos();

    form.addEventListener('submit', (e) => {
        e.preventDefault();

        const task = input.value.trim();
        
        if(!task) {
            alert('You definitely have something to do...')
            return
        }

        const todo = {
            content: task,
            // 使用时间戳生成唯一id,比随机数更可靠
            id: Date.now()
        }

        todos.push(todo);
        localStorage.setItem('todos', JSON.stringify(todos));
        
        // 清空输入框并重新渲染列表
        input.value = '';
        renderTodos();
    }); 
});

额外优化点

  • 用Date.now()生成任务id,比随机数更不容易重复
  • 给输入框和删除按钮添加dataset.id,方便精准匹配对应任务
  • 将事件绑定逻辑抽离成单独函数,避免重复代码

内容的提问来源于stack exchange,提问作者user379

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 02:40:30