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

如何在TodoList中通过e.target定位带唯一ID的生成Div并修改样式

解决TodoList多任务下Checkbox联动Input样式问题

问题背景

开发TodoList时,添加任务会生成带唯一ID的Div,需要实现:勾选任务内的Checkbox时,修改对应Input的背景色;取消勾选时恢复原状。原方案在多Checkbox场景下失效,现需无需知晓具体ID的定位方法,比如结合e.target.parentElement的DOM相对定位,或data-id配合querySelector的实现方式。

解决方案

方法1:DOM相对定位(无需额外ID/标识)

利用事件委托特性,点击Checkbox时,通过e.target获取当前触发事件的Checkbox,再通过DOM层级关系找到同任务内的Input。因为Checkbox和Input在同一个<li>元素下,直接通过父元素或兄弟元素定位即可:

function completeItem(e) {
  // 仅处理Checkbox的点击事件
  if (!e.target.matches('.checkbox')) return;

  // 找到当前任务项内的Input
  const todoInput = e.target.closest('.todo-item').querySelector('.generated-input');
  // 根据勾选状态切换样式类
  if (e.target.checked) {
    todoInput.classList.add('test');
  } else {
    todoInput.classList.remove('test');
  }
}

方法2:data-id关联标识

在生成任务元素时,给Checkbox和对应Input添加相同的data-id属性,后续通过该属性关联两者:

  1. 修改addToDoItem函数中生成li的代码:
li.innerHTML = `
  <input type="checkbox" class="checkbox" name="checkbox" data-id="${randomId}">
  <input type="text" class="generated-input" value="${toDoInput.value}" disabled="disabled" data-id="${randomId}">`;
  1. 修改completeItem函数:
function completeItem(e) {
  if (!e.target.matches('.checkbox')) return;

  const taskId = e.target.dataset.id;
  // 通过data-id找到对应Input
  const todoInput = document.querySelector(`.generated-input[data-id="${taskId}"]`);
  
  if (e.target.checked) {
    todoInput.classList.add('test');
  } else {
    todoInput.classList.remove('test');
  }
}

完整修改后的JS代码

const addButton = document.querySelector(".todo-button");
const toDoInput = document.querySelector(".todo-input");
const toDoUi = document.querySelector(".todo-list");
// 修正原代码选择器错误
const editBtn = document.querySelector(".edit-btn");

addButton.addEventListener("click", addToDoItem);
toDoUi.addEventListener("click", deleteItem);
toDoUi.addEventListener("click", completeItem);
toDoUi.addEventListener("click", editItem);

let randomId = "";

function getRandomId() {
  randomId = new Date().getTime().toString();
}

getRandomId();

function addToDoItem(event) {
  event.preventDefault();
  const div = document.createElement("div");
  div.classList.add("todo");
  const li = document.createElement("li");
  // 方法2使用下面的innerHTML,方法1保留原代码即可
  // li.innerHTML = `
  //   <input type="checkbox" class="checkbox" name="checkbox" data-id="${randomId}">
  //   <input type="text" class="generated-input" value="${toDoInput.value}" disabled="disabled" data-id="${randomId}">`;
  li.innerHTML = `
    <input type="checkbox" class="checkbox" name="checkbox" id="${randomId}">
    <input type="text" class="generated-input" value="${toDoInput.value}" disabled="disabled">`;
  li.classList.add("todo-item");
  div.append(li);

  getRandomId();

  const editButton = document.createElement("button");
  editButton.classList.add("edit-btn");
  editButton.innerText = "Edit";
  div.append(editButton);

  const deleteButton = document.createElement("button");
  deleteButton.classList.add("delete-btn");
  deleteButton.innerText = `Delete`;
  div.append(deleteButton);

  toDoUi.append(div);

  toDoInput.value = "";
}

function deleteItem(e) {
  if (e.target.classList[0] === "delete-btn") {
    const todo = e.target.parentElement;
    todo.remove();
  }
}

function editItem(e) {
  if (e.target.classList[0] === "edit-btn") {
    const todoItem = e.target.parentElement;
    const input = todoItem.querySelector(".generated-input");
    input.disabled = false;
    input.focus();
    e.target.classList.add("hideBtn");

    const saveButton = document.createElement("button");
    saveButton.className = "save-btn";
    saveButton.innerText = "Save";
    todoItem.firstChild.append(saveButton);

    // 直接绑定到当前saveButton,避免多任务时事件冲突
    saveButton.addEventListener("click", function saveItem() {
      input.disabled = true;
      saveButton.remove();
      e.target.classList.remove("hideBtn");
    });
  }
}

// 方法1的completeItem实现(替换为方法2则注释此段,启用下方方法2代码)
function completeItem(e) {
  if (!e.target.matches('.checkbox')) return;

  const todoInput = e.target.closest('.todo-item').querySelector('.generated-input');
  if (e.target.checked) {
    todoInput.classList.add('test');
  } else {
    todoInput.classList.remove('test');
  }
}

// 方法2的completeItem实现
// function completeItem(e) {
//   if (!e.target.matches('.checkbox')) return;

//   const taskId = e.target.dataset.id;
//   const todoInput = document.querySelector(`.generated-input[data-id="${taskId}"]`);
  
//   if (e.target.checked) {
//     todoInput.classList.add('test');
//   } else {
//     todoInput.classList.remove('test');
//   }
// }

说明

  • 方法1更简洁,依赖现有DOM结构关联性,无需额外添加标识,适合当前场景;
  • 方法2通过data-id明确关联元素,结构更清晰,适配复杂DOM场景;
  • 原代码中completeItem使用document.querySelector会选中页面第一个匹配元素,导致多任务失效,改为基于事件目标的相对定位即可解决问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 03:05:19