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

如何实现带动态切换图标及下方子任务列表的动态子任务输入框?

动态子任务功能实现方案

核心需求

  • 输入框默认显示**+**图标,触发子任务添加流程
  • 用户开始输入时,+图标替换为**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();
}

关键逻辑说明

  1. 状态切换:通过监听输入框的input事件,判断输入内容是否为空,切换操作图标的显示/隐藏状态
  2. 子任务管理:确认输入后动态创建DOM元素,为每个子任务绑定编辑和删除事件
  3. 编辑流程:点击铅笔图标切换到输入编辑模式,再次点击确认保存内容,恢复文本显示
  4. 样式控制:利用CSS的hidden类统一管理元素的显示状态,避免重复操作样式属性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 13:36:07