无法添加新行:ToDo列表无法生成独立任务卡片求助
解决ToDo列表任务卡片合并问题
你的问题出在复用了同一个任务卡片元素,并且直接把数组内容拼接成文本插入,没有为每个新任务创建独立的DOM元素。要实现每个任务一张独立卡片,需要动态生成新的任务卡片元素,而非复用初始的隐藏卡片。以下是具体修改方案:
1. 调整HTML结构
给每个分类卡片(ToDo/Doing/Done)添加任务容器,用来存放所有动态生成的任务卡片;同时把原有的.adding-task改成模板并隐藏:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>To do list- Projeto de alto escalão</title> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;500&display=swap" rel="stylesheet"> <link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" /> </head> <body> <h1>To do list</h1> <div class="cards"> <div class="card redd"> <p class="stats">🙂 To do</p> <!-- 新增:任务容器,用来存放所有动态生成的任务卡片 --> <div class="tasks-container"></div> <!-- 改为模板,隐藏起来 --> <div class="adding-task hide task-template"> <p class="task-descrip"></p> <span class="options"> <i class="fas fa-edit" style="margin-right: 2px;"></i> <i class="fas fa-trash-alt"></i> </span> </div> <!-- 添加data-target标记对应的数据数组 --> <button class="add-card" data-target="toDo"> + ADICIONAR TAREFAS </button> </div> <div class="card bluee"> <p class="stats">😀 Doing</p> <div class="tasks-container"></div> <div class="adding-task hide task-template"> <p class="task-descrip"></p> <span class="options"> <i class="fas fa-edit" style="margin-right: 2px;"></i> <i class="fas fa-trash-alt"></i> </span> </div> <button class="add-card" data-target="doing"> + ADICIONAR TAREFAS </button> </div> <div class="card pinkk"> <p class="stats">😎 Done</p> <div class="tasks-container"></div> <div class="adding-task hide task-template"> <p class="task-descrip"></p> <span class="options"> <i class="fas fa-edit" style="margin-right: 2px;"></i> <i class="fas fa-trash-alt"></i> </span> </div> <button class="add-card" data-target="done"> + ADICIONAR TAREFAS </button> </div> </div> <div class="overlay" id="overlay"> <div class="modal"> <div class="modal-title"> <p>Texto da nota</p> </div> <div class="input-text"> <input type="text" id="inputText"> </div> <button class="modal-button cancel" id="cancelButton">CANCELAR</button> <button class="modal-button" id="confirmButton">CONFIRMAR</button> </div> </div> </body> </html>
2. 修改CSS样式
给任务容器添加间距,让任务卡片排版更美观:
*{ margin: 0; padding: 0; box-sizing: border-box; } :root{ font-family: Arial, Helvetica, sans-serif; --red: rgb(247, 14, 14); --pink: rgb(218, 13, 133); --blue: rgb(55, 136, 243); } body{ background-color: #f1f1f1; padding: 2rem 2rem; } .cards{ display: flex; gap: 18px; padding-top: 1rem; height: fit-content; flex-wrap: wrap; } .card{ border-radius: 4px; width: 334px; padding: 1rem; max-width:100%; max-height: 100%; box-shadow: 3px 4px 10px rgba(0, 0, 0, 0.24); } .card.redd{ background-color: var(--red); } .card.bluee{ background-color: var(--blue); } .card.pinkk{ background-color: var(--pink); } .stats{ color: white; font-size: 22px; font-weight: 600; margin-right: 22px; margin-bottom: 15px; } .add-card{ border: none; background: none; color: white; font-weight: bold; font-size: 15px; cursor: pointer; margin-left: 4px; margin-top: 32px; } .overlay{ background-color: rgba(0, 0, 0, 0.5); top: 0; bottom: 0; left: 0; right: 0; display: flex; justify-content: center; align-items: center; display: none; } .overlay.in { display: flex; position: fixed; } .modal{ background-color: white; width: 700px; height: 170px; padding: 2rem 2rem; position: relative; } .modal-title{ font-weight: bold; font-size: 20px; margin-bottom: 30px; } #inputText{ background: none; border: none; border-bottom: 2px solid rgb(29, 96, 241); width: 100%; outline: none; font-size: 17px; } .modal-button{ border: none; background: none; color: rgb(25, 93, 240); font-weight: bold; font-size: 15px; cursor: pointer; position: absolute; right: 18px; bottom: 20px; } .modal-button.cancel{ margin-right: 107px; } .adding-task{ width:100%; height: fit-content; background-color: white; padding: 21px 15px; border-radius: 6px; display: flex; justify-content: space-between; gap: 18px; } .adding-task.hide{ display: none; } .task-descrip{ font-weight: bold; font-size: 15px; font-family: 'Open Sans', sans-serif; word-wrap: break-word; word-break: break-all; } .options{ cursor: pointer; } /* 新增:任务容器样式 */ .tasks-container { display: flex; flex-direction: column; gap: 12px; margin-bottom: 20px; }
3. 重写JavaScript逻辑
核心修改:动态克隆任务模板生成新卡片,记录当前要添加任务的目标分类,同步更新数据和DOM:
//CRUD (Create, Read, Update, Delete) -> allows you to create data, read data, edit it, and delete those data. // Passo 1: mostrar o MODAL (CREATE) const overlay = document.querySelector('.overlay'); let currentTargetContainer = null; // 当前要添加任务的容器 let currentDataKey = null; // 当前要添加到的数据数组键名 function showModal() { overlay.classList.add("in"); } // Passo 2: Esconder o MODAL function hideModal() { overlay.classList.remove("in"); input.value = ""; // 清空输入框 } //Passo 3: CHAMAR AS FUNÇÕES Quando clicamos no botão const buttons = document.querySelectorAll(".add-card"); buttons.forEach((btn) => { btn.onclick = (event) => { showModal(); // 获取当前按钮对应的卡片容器和数据键名 currentDataKey = btn.dataset.target; currentTargetContainer = btn.parentElement.querySelector('.tasks-container'); } }) const modalCancel = document.querySelector('.modal-button.cancel'); modalCancel.addEventListener('click', hideModal); //Passo 4 - Fazer o botão CONFIRMAR funcionar & pegar o valor do input; const modalConfirm = document.querySelector('#confirmButton'); let input = document.getElementById('inputText'); const taskTemplate = document.querySelector('.task-template'); // 获取任务模板 const data = { toDo: [], doing: [], done: [] }; // 创建新任务卡片的函数 function createTaskCard(taskText) { // 克隆模板节点,true表示克隆所有子元素 const newTaskCard = taskTemplate.cloneNode(true); newTaskCard.classList.remove('hide', 'task-template'); // 移除隐藏和模板类 // 设置任务文本 newTaskCard.querySelector('.task-descrip').textContent = taskText; // 添加删除按钮事件 newTaskCard.querySelector('.fa-trash-alt').addEventListener('click', () => { // 从数据数组中移除该任务 data[currentDataKey] = data[currentDataKey].filter(item => item !== taskText); // 移除DOM元素 newTaskCard.remove(); }); return newTaskCard; } //Passo 5 - Adicionar alguma tarefa no container; function confirmButton() { modalConfirm.addEventListener('click', () => { hideModal(); const inputValue = input.value.trim(); if (!inputValue) return; // 空输入不处理 // 更新数据数组 data[currentDataKey].push(inputValue); // 创建新任务卡片并添加到目标容器 const newCard = createTaskCard(inputValue); currentTargetContainer.appendChild(newCard); }); } confirmButton();
关键修改点说明
- 动态生成卡片:不再复用单个任务卡片,而是通过克隆模板创建新的独立DOM元素,每个任务对应一张卡片
- 分类关联:用
data-target属性关联添加按钮和对应的数据数组,支持三个分类的任务添加 - 数据同步:添加/删除任务时同步更新数据数组和DOM元素
- 空输入校验:避免添加空任务
内容的提问来源于stack exchange,提问作者olamundo97
相关产品推荐
相关产品推荐

