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

使用Ajax将待办列表条目存入数据库解决页面刷新数据丢失问题

方案1:使用localStorage实现本地持久化(无需后端,最适合新手场景)

localStorage是浏览器自带的本地存储能力,无需额外服务端代码即可实现刷新后数据不丢失,只需要修改你的JS代码,增加存储、读取、更新本地数据的逻辑即可,完整修改后的代码如下:

//selectors
const todoInput = document.querySelector('.todo_input');
const todoButton = document.querySelector('.todo_button');
const todoList = document.querySelector('.todo_list');
const filterOption = document.querySelector('.filter_todo');

//event listeners
document.addEventListener('DOMContentLoaded', getLocalTodos); // 页面加载先读本地数据
todoButton.addEventListener("click", addTodo)
todoList.addEventListener("click", deleteCheck)
filterOption.addEventListener("click", filterTodo)

//functions
function addTodo(event) {
    event.preventDefault();
    if(todoInput.value === ""){
        return null
    }
    //todo DIV
    const todoDiv = document.createElement('div');
    todoDiv.classList.add('todo'); 

    //todo LI 
    const newTodo = document.createElement('li');
    newTodo.innerText = todoInput.value;
    newTodo.classList.add('todo_item');
    todoDiv.appendChild(newTodo);

    //check mark BUTTON
    const completedButton = document.createElement('button');
    completedButton.innerHTML = '<i class="fas fa-check"></i>';
    completedButton.classList.add('complete_btn')
    todoDiv.appendChild(completedButton);

    //delete BUTTON
    const deleteButton = document.createElement('button');
    deleteButton.innerHTML = '<i class="fas fa-trash"></i>';
    deleteButton.classList.add('delete_btn')
    todoDiv.appendChild(deleteButton);

    //Append to Actual LIST
    todoList.appendChild(todoDiv);
    // 保存到本地存储
    saveLocalTodos(newTodo.innerText);
    //Clear todo input VALUE
    todoInput.value = ""
}

//DELETE & CHECK
function deleteCheck(e) {
    const item = e.target;

    //DELETE ITEM
    if (item.classList[0] === "delete_btn") {
        const todo = item.parentElement;
        // 先删本地存储的数据
        removeLocalTodos(todo);
        //ANIMATION TRANSITION
        todo.classList.add("fall")
        todo.addEventListener('transitionend', function () {
            todo.remove()
        })
    }

    //COMPLETE ITEM
    if (item.classList[0] === "complete_btn") {
        const todo = item.parentElement;
        todo.classList.toggle("completedItem")
        // 更新本地存储的完成状态
        updateLocalTodoStatus(todo);
    }
}

//FILTERING THE TASKS ACCORDING THE OPTION
function filterTodo(e) {
    const todos = todoList.childNodes;
    for(let i = 1; i<todos.length; i++ ){
        switch (e.target.value) {

            case "all":
                todos[i].style.display = "flex";
                break;

            case "completed":
                if (todos[i].classList.contains('completedItem')) {
                    todos[i].style.display = "flex";
                } else {
                    todos[i].style.display = "none";
                }
                break;
                
            case "uncompleted":
                if (!todos[i].classList.contains('completedItem')) {
                    todos[i].style.display = "flex";
                } else {
                    todos[i].style.display = "none";
                }
                break;
        }
    }
} 

// -------------localStorage相关工具函数-------------
// 保存新待办到本地
function saveLocalTodos(todoText) {
    let todos = JSON.parse(localStorage.getItem('todos')) || [];
    todos.push({text: todoText, completed: false});
    localStorage.setItem('todos', JSON.stringify(todos));
}

// 读取本地待办渲染到页面
function getLocalTodos() {
    let todos = JSON.parse(localStorage.getItem('todos')) || [];
    todos.forEach(todo => {
        const todoDiv = document.createElement('div');
        todoDiv.classList.add('todo'); 
        if(todo.completed) todoDiv.classList.add('completedItem');

        const newTodo = document.createElement('li');
        newTodo.innerText = todo.text;
        newTodo.classList.add('todo_item');
        todoDiv.appendChild(newTodo);

        const completedButton = document.createElement('button');
        completedButton.innerHTML = '<i class="fas fa-check"></i>';
        completedButton.classList.add('complete_btn')
        todoDiv.appendChild(completedButton);

        const deleteButton = document.createElement('button');
        deleteButton.innerHTML = '<i class="fas fa-trash"></i>';
        deleteButton.classList.add('delete_btn')
        todoDiv.appendChild(deleteButton);

        todoList.appendChild(todoDiv);
    })
}

// 删除本地存储的对应待办
function removeLocalTodos(todoEl) {
    let todos = JSON.parse(localStorage.getItem('todos')) || [];
    const targetText = todoEl.querySelector('.todo_item').innerText;
    todos = todos.filter(todo => todo.text !== targetText);
    localStorage.setItem('todos', JSON.stringify(todos));
}

// 更新本地待办的完成状态
function updateLocalTodoStatus(todoEl) {
    let todos = JSON.parse(localStorage.getItem('todos')) || [];
    const targetText = todoEl.querySelector('.todo_item').innerText;
    const targetIndex = todos.findIndex(todo => todo.text === targetText);
    todos[targetIndex].completed = !todos[targetIndex].completed;
    localStorage.setItem('todos', JSON.stringify(todos));
}

小提示:你可以把HTML里写死的Tomatoes默认待办删掉,避免和localStorage渲染的内容重复,如果需要保留默认值,在getLocalTodos函数里判断todos为空的时候主动加进去即可。


方案2:使用AJAX实现服务端持久化(多设备同步需要)

如果需要跨设备访问同一份待办数据,才需要用到AJAX方案,前提是你先写好对应的后端接口,包括:

  • 待办列表获取接口:GET请求返回所有待办的JSON数组
  • 新增待办接口:POST请求接收待办文本、完成状态,写入数据库
  • 删除待办接口:请求接收待办唯一标识,删除对应数据库记录
  • 状态更新接口:请求接收待办唯一标识、新状态,更新数据库记录

新增待办的AJAX示例(用原生fetch实现):

// 可以替换到addTodo函数里保存localStorage的位置
fetch('/save_todo.php', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    text: newTodo.innerText,
    completed: false
  })
}).then(res => res.json())
.then(data => {
  // 接口返回成功后的处理逻辑
})

初学建议先把localStorage方案跑通,再学习AJAX相关的后端交互逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 00:18:04