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

点击待办列表项编辑时删除按钮消失问题求助(附代码)

Todo List编辑功能修复方案

问题描述

我正在开发一个简单的Todo List,目标是点击列表项即可编辑对应条目。当前存在两个问题:

  • 添加条目时,删除按钮能正常显示在条目旁;
  • 点击列表项弹出编辑文本框时,删除按钮被覆盖,布局混乱。
    我推测是事件冒泡导致的,但不知道具体解决方法。

原始代码

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>To-do List</title>
  </head>
  <body>
    <header></header>
    <main>
      <h1>To-do List</h1>
      <form action="#" id="form">
        <label for="task">Enter your task:</label>
        <input type="text" id="task" required />
        <button type="submit">Add Task</button>
      </form>
      <ul id="list"></ul>
    </main>
    <footer></footer>
    <script src="app.js"></script>
  </body>
</html>

JavaScript

const form = document.getElementById('form');
const list = document.getElementById('list');

form.addEventListener('submit', function (event) {
    event.preventDefault();

    const taskInput = document.getElementById('task');
    const todo = taskInput.value;

    const listItem = document.createElement('li');
    listItem.textContent = todo;

    list.appendChild(listItem);

    taskInput.value = '';
    const deleteButton = document.createElement('button');
    deleteButton.innerHTML = 'Delete';
    listItem.appendChild(deleteButton);

    deleteButton.addEventListener('click', function () {
        list.removeChild(listItem);
    });
});

list.addEventListener('click', function (event) {
    const listItem = event.target;

    if (listItem.tagName === 'LI') {
        const text = listItem.textContent;
        listItem.innerHTML = ''; // Clear the list item content

        const inputElement = document.createElement('input');
        inputElement.type = 'text';
        inputElement.value = text;
        listItem.appendChild(inputElement);

        inputElement.focus();

        inputElement.addEventListener('blur', function () {
            const newText = inputElement.value;
            listItem.removeChild(inputElement);

            listItem.textContent = newText; // Update the list item text
            inputElement.removeEventListener('blur', onBlur);           
        });
       
        function onBlur() {
            const newText = inputElement.value;
            listItem.removeChild(inputElement);
            listItem.textContent = newText; // Update the list item text
            inputElement.removeEventListener('blur', onBlur);
        }
        inputElement.addEventListener('blur', onBlur);
    }
});

问题分析

  1. 布局破坏:点击<li>时执行listItem.innerHTML = '',直接清空了列表项内的所有内容(包括删除按钮),导致编辑状态下删除按钮消失,退出编辑后也无法恢复。
  2. 事件冒泡隐患:点击删除按钮时,事件会向上冒泡到<li>元素,触发编辑逻辑,这会导致误操作。
  3. 重复事件绑定:代码中给输入框绑定了两次blur事件,属于冗余逻辑。

修复后的代码

JavaScript

const form = document.getElementById('form');
const list = document.getElementById('list');

form.addEventListener('submit', function (event) {
    event.preventDefault();

    const taskInput = document.getElementById('task');
    const todo = taskInput.value.trim();
    if (!todo) return;

    // 重构列表项结构:文本容器 + 删除按钮
    const listItem = document.createElement('li');
    const taskTextSpan = document.createElement('span');
    taskTextSpan.className = 'task-text';
    taskTextSpan.textContent = todo;
    listItem.appendChild(taskTextSpan);

    const deleteButton = document.createElement('button');
    deleteButton.textContent = 'Delete';
    listItem.appendChild(deleteButton);

    list.appendChild(listItem);
    taskInput.value = '';

    // 删除按钮逻辑:阻止冒泡 + 删除条目
    deleteButton.addEventListener('click', function (event) {
        event.stopPropagation(); // 阻止事件冒泡到li
        list.removeChild(listItem);
    });
});

list.addEventListener('click', function (event) {
    // 只响应点击文本容器的情况
    const taskTextSpan = event.target.closest('.task-text');
    if (!taskTextSpan) return;

    const listItem = taskTextSpan.parentElement;
    const originalText = taskTextSpan.textContent;

    // 创建输入框替换文本容器
    const inputElement = document.createElement('input');
    inputElement.type = 'text';
    inputElement.value = originalText;
    listItem.replaceChild(inputElement, taskTextSpan);
    inputElement.focus();

    // 失去焦点时保存编辑内容
    inputElement.addEventListener('blur', function () {
        const newText = inputElement.value.trim();
        // 替换回文本容器,保留删除按钮
        const newTaskTextSpan = document.createElement('span');
        newTaskTextSpan.className = 'task-text';
        newTaskTextSpan.textContent = newText || originalText; // 空值则保留原文本
        listItem.replaceChild(newTaskTextSpan, inputElement);
    });

    // 按下回车也保存编辑
    inputElement.addEventListener('keydown', function (event) {
        if (event.key === 'Enter') {
            inputElement.blur();
        }
    });
});

关键修改说明

  • 分离结构:用<span class="task-text">单独承载任务文本,编辑时只替换这个元素,保留删除按钮的布局;
  • 阻止冒泡:删除按钮点击事件中添加event.stopPropagation(),避免触发父元素<li>的编辑逻辑;
  • 优化编辑逻辑:使用replaceChild替换元素,而非清空整个列表项内容,保证布局完整性;
  • 增加回车保存:支持按下回车完成编辑,提升用户体验;
  • 空值处理:编辑后为空时保留原文本,避免出现空条目。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 13:50:35