如何实现带动态切换图标及下方子任务列表的动态子任务输入框?
动态子任务功能实现方案
核心需求
- 输入框默认显示**+**图标,触发子任务添加流程
- 用户开始输入时,+图标替换为**X(取消)和✓(确认)**按钮
- 点击✓按钮,输入内容作为子任务追加到输入框下方
- 每个子任务支持**编辑(铅笔图标)和删除(垃圾桶图标)**操作
完整实现代码
HTML 结构
<div class="subtask-container"> <!-- 输入区域 --> <div class="input-wrapper"> <input type="text" id="subtask-input" placeholder="添加子任务..." /> <div class="input-actions"> <span class="icon add-icon">+</span> <span class="icon cancel-icon hidden">×</span> <span class="icon confirm-icon hidden">✓</span> </div> </div> <!-- 子任务列表 --> <ul id="subtask-list"></ul> </div>
CSS 样式
/* 基础容器样式 */ .subtask-container { max-width: 400px; margin: 20px; font-family: Arial, sans-serif; } /* 输入区域布局 */ .input-wrapper { display: flex; align-items: center; gap: 8px; padding: 8px 12px; border: 1px solid #ddd; border-radius: 4px; } #subtask-input { flex: 1; border: none; outline: none; font-size: 14px; } /* 图标通用样式 */ .icon { cursor: pointer; font-size: 16px; user-select: none; } .add-icon { color: #2563eb; } .cancel-icon { color: #dc2626; } .confirm-icon { color: #16a34a; } /* 隐藏类 */ .hidden { display: none; } /* 子任务列表样式 */ #subtask-list { list-style: none; padding: 0; margin-top: 12px; } .subtask-item { display: flex; align-items: center; justify-content: space-between; padding: 8px 12px; border: 1px solid #eee; border-radius: 4px; margin-bottom: 8px; } .subtask-content { flex: 1; margin-right: 12px; font-size: 14px; } .subtask-content input { width: 100%; border: 1px solid #ddd; border-radius: 4px; padding: 4px 6px; font-size: 14px; } .subtask-actions { display: flex; gap: 8px; } .edit-icon { color: #f59e0b; } .delete-icon { color: #dc2626; }
JavaScript 逻辑
const input = document.getElementById('subtask-input'); const addIcon = document.querySelector('.add-icon'); const cancelIcon = document.querySelector('.cancel-icon'); const confirmIcon = document.querySelector('.confirm-icon'); const subtaskList = document.getElementById('subtask-list'); // 输入状态切换:显示确认/取消按钮,隐藏+图标 input.addEventListener('input', () => { if (input.value.trim()) { addIcon.classList.add('hidden'); cancelIcon.classList.remove('hidden'); confirmIcon.classList.remove('hidden'); } else { resetInputState(); } }); // 取消操作:清空输入,恢复初始状态 cancelIcon.addEventListener('click', resetInputState); // 确认操作:添加子任务 confirmIcon.addEventListener('click', () => { const taskText = input.value.trim(); if (!taskText) return; // 创建子任务DOM元素 const li = document.createElement('li'); li.className = 'subtask-item'; li.innerHTML = ` <div class="subtask-content"> <span class="task-text">${taskText}</span> <input type="text" class="edit-input hidden" value="${taskText}" /> </div> <div class="subtask-actions"> <span class="icon edit-icon">✏️</span> <span class="icon delete-icon">🗑️</span> </div> `; // 绑定编辑事件 const editIcon = li.querySelector('.edit-icon'); const taskTextEl = li.querySelector('.task-text'); const editInput = li.querySelector('.edit-input'); editIcon.addEventListener('click', () => { const isEditing = taskTextEl.classList.contains('hidden'); if (isEditing) { // 保存编辑内容 const newText = editInput.value.trim(); if (newText) { taskTextEl.textContent = newText; } taskTextEl.classList.remove('hidden'); editInput.classList.add('hidden'); editIcon.textContent = '✏️'; } else { // 进入编辑状态 taskTextEl.classList.add('hidden'); editInput.classList.remove('hidden'); editInput.focus(); editIcon.textContent = '✓'; } }); // 绑定删除事件 const deleteIcon = li.querySelector('.delete-icon'); deleteIcon.addEventListener('click', () => { li.remove(); }); // 添加到列表 subtaskList.appendChild(li); resetInputState(); }); // 重置输入框状态 function resetInputState() { input.value = ''; addIcon.classList.remove('hidden'); cancelIcon.classList.add('hidden'); confirmIcon.classList.add('hidden'); input.focus(); }
关键逻辑说明
- 状态切换:通过监听输入框的
input事件,判断输入内容是否为空,切换操作图标的显示/隐藏状态 - 子任务管理:确认输入后动态创建DOM元素,为每个子任务绑定编辑和删除事件
- 编辑流程:点击铅笔图标切换到输入编辑模式,再次点击确认保存内容,恢复文本显示
- 样式控制:利用CSS的
hidden类统一管理元素的显示状态,避免重复操作样式属性
内容的提问来源于stack exchange,提问作者Damir Buron
相关产品推荐
相关产品推荐

