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

开发Todo List时点击X按钮无法关闭条目问题求助

Todo List条目关闭按钮失效问题解决

开发一款Todo List应用时,遇到点击条目上的X按钮无法移除对应条目的问题,预期点击该按钮时可删除对应的待办条目。以下是原始实现代码:

原始代码

HTML

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>todo list</title>
  <link rel="stylesheet" href="/quiz/quiz.css">
</head>

<body>

  <div id="container">
    <button class="js-button">Make a note</button>
  </div>

  <div class="pops">
    <span class="js-exit">X</span>
    <div class="inner-pops">
      <div class="ultra-inner-pops">
        <h2>Title</h2>
        <input id="get-title" type="text">
      </div>

      <div class="ultra-inner-pops">
        <h2>Description</h2>
        <textarea id="get-paragraph" cols="30" rows="15"></textarea>
      </div>
      <button class="js-enter-btn">Enter</button>
    </div>
  </div>

  <div id="note-container">

  </div>

  <script src="/quiz/quiz.js"></script>
</body>

</html>

CSS

* {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
}

body {
  background: rgb(1, 1, 93);
  position: relative;
  padding: 20px 5%;
}

#container {
  padding: 30px 10%;
}

#container button {
  color: white;
  background-color: rgb(192, 0, 192);
  padding: 10px 30px;
  font-size: 1.2rem;
  border-radius: 10px;
  transition: transform 0.5s, background-color 0.5s;
  border: none;
}

#container button:hover {
  transform: translateY(-5px);
  background-color: rgb(253, 148, 253);
}

.pops {
  padding: 30px 3%;
  width: 30%;
  height: 65vh;
  overflow: hidden;
  background-color: rgb(115, 115, 115);
  border-radius: 10px;
  position: absolute;
  left: 30%;
  display: none;
}

.pops.active-pops {
  display: block;
}

.pops span {
  color: red;
  font-size: 1.7rem;
  margin-left: 100%;
  cursor: pointer;
}

.pops .inner-pops {
  width: 100%;
}

.pops .inner-pops button {
  padding: 5px 14px;
  font-size: 1.2rem;
}

.pops .ultra-inner-pops {
  color: white;
  margin-top: 20px;
  overflow: hidden;
}

.pops .ultra-inner-pops input {
  width: 100%;
  padding: 10px;
}

.pops .ultra-inner-pops textarea {
  width: 100%;
}

#note-container {
  display: flex;
  flex-wrap: wrap;
  gap: 1%;
}

#note-container .your-note {
  width: 30%;
  margin-top: 3%;
}

#note-container .your-note .container {
  background: linear-gradient(rgb(40, 197, 202), rgb(209, 0, 228));
  padding: 15px 30px;
  word-wrap: break-word;
  height: 100%;
}

#note-container .your-note .container h2 {
  margin-bottom: 15px;
  font-size: 2rem;
  font-weight: 600;
  text-align: center;
}

#note-container .your-note .container p {
  font-weight: 500;
}

#note-container .your-note .container span {
  margin-left: 100%;
  color: red;
  cursor: pointer;
}

JavaScript

const displayNote = document.querySelector('.js-button');
const clearNote = document.querySelector('.js-exit');
const closeButton = document.querySelectorAll('#get-close');

function exit() {
  document.querySelector('.pops').classList.remove('active-pops');
}

function openNote() {
  document.querySelector('.pops').classList.add('active-pops');
}

clearNote.addEventListener('click', () => {
  exit();
});

displayNote.addEventListener('click', () => {
  openNote();
});


function putNewContext() {
  const title = document.querySelector('#get-title');
  const paragraph = document.querySelector('#get-paragraph');

  let html = `
  <div class="your-note">
  <div class="container">
    <span id="get-close">X</span>
    <h2>${title.value}</h2>
    <p>${paragraph.value}</p>
  </div>
</div>
  `;

  return html;
}

document.querySelector('.js-enter-btn').addEventListener('click', () => {
  document.querySelector('#note-container').innerHTML += putNewContext();
});


function attachCloseListeners() {
  const closeButton = document.querySelectorAll('#get-close');
  closeButton.forEach((button) => {
    button.addEventListener('click', () => {
      button.parentNode.parentNode.remove(); // Removes the entire note container
    });
  });
}

attachCloseListeners();

问题原因

  1. 动态元素未绑定事件:页面初始化时执行attachCloseListeners(),仅给当时存在的元素绑定了点击事件,但后续新增的条目是动态生成的,这些元素没有被绑定事件。
  2. 重复使用ID:多个关闭按钮使用同一个id="get-close",HTML规范中ID必须唯一,这会导致选择器无法正确选中所有目标元素,引发行为异常。

解决方法(事件委托方案,更优)

利用事件冒泡机制,监听父容器#note-container的点击事件,无需每次新增条目都重新绑定事件,同时修正ID重复问题:

修改后的JavaScript代码

const displayNote = document.querySelector('.js-button');
const clearNote = document.querySelector('.js-exit');

function exit() {
  document.querySelector('.pops').classList.remove('active-pops');
}

function openNote() {
  document.querySelector('.pops').classList.add('active-pops');
}

clearNote.addEventListener('click', () => {
  exit();
});

displayNote.addEventListener('click', () => {
  openNote();
});


function putNewContext() {
  const title = document.querySelector('#get-title');
  const paragraph = document.querySelector('#get-paragraph');

  // 将id改为class,避免重复ID
  let html = `
  <div class="your-note">
  <div class="container">
    <span class="get-close">X</span>
    <h2>${title.value}</h2>
    <p>${paragraph.value}</p>
  </div>
</div>
  `;

  return html;
}

document.querySelector('.js-enter-btn').addEventListener('click', () => {
  document.querySelector('#note-container').innerHTML += putNewContext();
});

// 使用事件委托,监听父容器的点击事件
document.querySelector('#note-container').addEventListener('click', (e) => {
  // 判断点击的元素是否是关闭按钮
  if (e.target.classList.contains('get-close')) {
    // 移除对应的条目
    e.target.closest('.your-note').remove();
  }
});

对应CSS修改(可选,仅调整选择器,不影响样式)

将原CSS中针对#get-close的选择器改为.get-close:

#note-container .your-note .container span.get-close {
  margin-left: 100%;
  color: red;
  cursor: pointer;
}

说明

  • 事件委托通过监听父元素的事件,利用冒泡机制处理子元素的点击,无论新增多少条目,都能自动绑定关闭事件,无需重复执行绑定逻辑。
  • 使用closest('.your-note')可以更精准地找到要移除的条目容器,比parentNode.parentNode更健壮,避免DOM结构变化导致代码失效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 09:18:10